1. 程式人生 > >Risk UVA - 12264 拆點法+最大流+二分

Risk UVA - 12264 拆點法+最大流+二分

sizeof main net style ati continue ons class tps

/**
題目: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[N]; bool vis[N]; int d[N]; int cur[N]; 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[N][N]; int sd[N], f[N][N]; int weak[N], enemy[N]; 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; }

Risk UVA - 12264 拆點法+最大流+二分