您的位置:首页 > 其它

Risk UVA - 12264 拆点法+最大流+二分 最少流量的节点流量尽量多。

2017-07-20 20:00 776 查看
/**
题目:Risk UVA - 12264
链接:https://vjudge.net/problem/UVA-12264
题意:给n个点的无权无向图(n<=100),每个点有一个非负数ai。
若ai==0则此点归敌方所有,若ai>0则此点归你且上面有ai个属于你的士兵。
保证至少有一个属于你的点与敌方的点相邻。你可以让你的每个士兵最多移动一次
,每次可以待在原地或者去到相邻的属于你的领地,但每个点至少要留1各士兵,
使得最薄弱的关口尽量坚固。关口是指与敌方点相邻的点,薄弱与坚固分别指兵少与兵多。

思路:拆点法+最大流+二分。

将点x,拆分成x,x'。
s->x,容量为初始士兵数量。
x'->t。 如果x是薄弱点,那么容量为mid,否则容量为1。1是为了满足题目至少留一个兵。
x->x',容量为INF。

如果x与y相邻,x->y',容量为INF。

上面的容量为mid,就是假如所有的薄弱点都为mid个士兵,是否可行,如果可行,那么增加mid,找一个满足的最大的mid。

二分mid。

如果最大流=薄弱点数量*mid+(自己的领地结点数-薄弱点数量)*1。那么可行。

注意:原题题意给出的输入输出要求是没有问题的,不过题目的实际输入输出有点问题。照着题意要求做就行。

*/
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const long long MAS = 1e13;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int N = 205;///拆点法,注意要乘以个2.
struct Edge{
int from, to, cap, flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct Dinic{
int n, m, s, t;
vector<Edge> edges;
vector<int> G
;
bool vis
;
int d
;
int cur
;

void init(int n)
{
this->n = n;
for(int i = 0; i <= n; i++) G[i].clear();
edges.clear();
}

void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}

bool BFS()
{
memset(vis, 0, sizeof vis);
queue<int> Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i = 0; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}

int DFS(int x,int a)
{
if(x==t||a==0) return a;
int flow = 0, f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a==0) break;
}
}
return flow;
}

int Maxflow(int s,int t)
{
this->s = s, this->t = t;
int flow = 0;
while(BFS())
{
memset(cur, 0, sizeof cur);
flow += DFS(s,INF);
}
return flow;
}
};
char str

;
int sd
, f

;
int weak
, enemy
;
int main()
{
int n, k;
cin>>k;
while(k--){
scanf("%d",&n);
memset(enemy, 0, sizeof enemy);
for(int i = 1; i <= n; i++){
scanf("%d",&sd[i]);
if(sd[i]==0) enemy[i] = 1;///敌人结点
}
memset(f, 0, sizeof f);
memset(weak, 0, sizeof weak);
for(int i = 1; i <= n; i++){
scanf("%s",str[i]+1);
for(int j = 1; j <= n; j++){
if(str[i][j]=='Y'){
f[i][j] = 1;
if(enemy[i]&&enemy[j]==0){
weak[j] = 1;///薄弱结点
}
if(enemy[i]==0&&enemy[j]){
weak[i] = 1;///薄弱结点
}
}
}
}
int s = 0, t = n*2+1;
Dinic dinic, save;
dinic.init(t);
for(int i = 1; i <= n; i++){
if(enemy[i]) continue;
dinic.AddEdge(s,i,sd[i]);
dinic.AddEdge(i,i+n,INF);
if(weak[i]==0){
dinic.AddEdge(i+n,t,1);
}
}
for(int i = 1; i <= n; i++){
if(enemy[i]) continue;
for(int j = 1; j <= n; j++){
if(enemy[j]) continue;
if(f[i][j]){
dinic.AddEdge(i,j+n,INF);
}
}
}

save = dinic;
int weaknum = 0, total = 0;
for(int i = 1; i <= n; i++){
if(weak[i]) weaknum++;
if(enemy[i]==0) total++;
}
int lo = 0, hi = INF, mid;
int ans;
while(lo<=hi){
mid = (lo+hi)/2;
dinic = save;
for(int i = 1; i <= n; i++){
if(weak[i]){
dinic.AddEdge(i+n,t,mid);
}
}
int mas = dinic.Maxflow(s,t);
int sum = weaknum*mid+(total-weaknum);
if(mas==sum){
lo = mid+1;
ans = mid;
}else
{
hi = mid-1;
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: