標籤:algorithm 圖論 網路流
http://poj.org/problem?id=1815
Friendship
| Time Limit: 2000MS |
|
Memory Limit: 20000K |
| Total Submissions: 9026 |
|
Accepted: 2534 |
Description In modern society, each person has his own friends. Since all the people are very busy, they communicate with each other only by phone. You can assume that people A can keep in touch with people B, only if
1. A knows B‘s phone number, or
2. A knows people C‘s phone number and C can keep in touch with B.
It‘s assured that if people A knows people B‘s number, B will also know A‘s number.
Sometimes, someone may meet something bad which makes him lose touch with all the others. For example, he may lose his phone number book and change his phone number at the same time.
In this problem, you will know the relations between every two among N people. To make it easy, we number these N people by 1,2,...,N. Given two special people with the number S and T, when some people meet bad things, S may lose touch with T. Your job is to compute the minimal number of people that can make this situation happen. It is supposed that bad thing will never happen on S or T.
Input The first line of the input contains three integers N (2<=N<=200), S and T ( 1 <= S, T <= N , and S is not equal to T).Each of the following N lines contains N integers. If i knows j‘s number, then the j-th number in the (i+1)-th line will be 1, otherwise the number will be 0.
You can assume that the number of 1s will not exceed 5000 in the input.
Output If there is no way to make A lose touch with B, print "NO ANSWER!" in a single line. Otherwise, the first line contains a single number t, which is the minimal number you have got, and if t is not zero, the second line is needed, which contains t integers in ascending order that indicate the number of people who meet bad things. The integers are separated by a single space.
If there is more than one solution, we give every solution a score, and output the solution with the minimal score. We can compute the score of a solution in the following way: assume a solution is A1, A2, ..., At (1 <= A1 < A2 <...< At <=N ), the score will be (A1-1)*N^t+(A2-1)*N^(t-1)+...+(At-1)*N. The input will assure that there won‘t be two solutions with the minimal score.
Sample Input
3 1 31 1 01 1 10 1 1
Sample Output
12
Source POJ Monthly |
題意:
給出無向圖,1表示有邊,0表示沒有邊,現在要消去一些點,使得給出的A,B兩點不相連,A和B不校區,問最少消去多少個點,並升序輸出方案,有多種方案則輸出 (A1-1)*N^t+(A2-1)*N^(t-1)+...+(At-1)*N最小的方案。
分析:
無向圖中消去最少的點使兩點割開,可以使用最小割求解。
將一個點拆成入點和出點,之間連一條容量為一的邊。圖中原有的邊按照出->入連一條容量為無窮大的邊,A的出點為源點,B的入點為匯點,求出其最小割即為要消去的點的數量。
具體方案的輸出看上去比較複雜,仔細分析實際上是一個N進位數,使這個數最小,就是其“字典序”最小。我們從小到大枚舉每一個點,如果將這個點(這個點拆出的邊)去掉後的最小割小於原最小割,那麼這個點(這個點拆出的邊)屬於最小割集。如此便可求出最後的結果。
那麼是不是每個點都一定要枚舉嗎?我們考慮如下命題:最小割集中的邊是滿流邊;其逆命題:滿流邊是最小割集中的邊,別想了,這顯然是否定的;其逆否命題:非滿流邊一定不屬於最小割集,這才是我們要的命題。也就是說如果一個點拆出的邊不滿流,那它一定不構成最小割,所以這個點我們根本不用check。
#include<cstdio>#include<iostream>#include<cstdlib>#include<algorithm>#include<ctime>#include<cctype>#include<cmath>#include<string>#include<cstring>#include<stack>#include<queue>#include<list>#include<vector>#include<map>#include<set>#define sqr(x) ((x)*(x))#define LL long long#define itn int#define INF 0x3f3f3f3f#define PI 3.1415926535897932384626#define eps 1e-10#define maxm 200007#define maxn 404using namespace std;int fir[maxn];int u[maxm],v[maxm],cap[maxm],flow[maxm],nex[maxm];int e_max;int iter[maxn],q[maxn],lv[maxn];void add_edge(int _u,int _v,int _w){ int e; e=e_max++; u[e]=_u;v[e]=_v;cap[e]=_w; nex[e]=fir[u[e]];fir[u[e]]=e; e=e_max++; u[e]=_v;v[e]=_u;cap[e]=0; nex[e]=fir[u[e]];fir[u[e]]=e;}void dinic_bfs(int s){ int f,r; memset(lv,-1,sizeof lv); q[f=r=0]=s; lv[s]=0; while(f<=r) { int x=q[f++]; for (int e=fir[x];~e;e=nex[e]) { if (cap[e]>flow[e] && lv[v[e]]<0) { lv[v[e]]=lv[u[e]]+1; q[++r]=v[e]; } } }}int dinic_dfs(int _u,int t,int _f){ if (_u==t) return _f; for (int &e=iter[_u];~e;e=nex[e]) { if (cap[e]>flow[e] && lv[_u]<lv[v[e]]) { int _d=dinic_dfs(v[e],t,min(_f,cap[e]-flow[e])); if (_d>0) { flow[e]+=_d; flow[e^1]-=_d; return _d; } } } return 0;}int max_flow(int s,int t){ memset(flow,0,sizeof flow); int total_flow=0; for (;;) { dinic_bfs(s); if (lv[t]<0) return total_flow; memcpy(iter,fir,sizeof iter); int _f; while ((_f=dinic_dfs(s,t,INF))>0) total_flow+=_f; } return total_flow;}int that_edge[maxn];int main(){ #ifndef ONLINE_JUDGE freopen("/home/fcbruce/文檔/code/t","r",stdin); #endif // ONLINE_JUDGE int n,_u,_v,_w,s,t; scanf("%d%d%d",&n,&_u,&_v); s=_u+n;t=_v; e_max=0; memset(fir,-1,sizeof fir); for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { scanf("%d",&_w); if (!_w) continue; if (i==_u && j==_v || i==_v && j==_u) { printf("NO ANSWER!\n"); return 0; } add_edge(i+n,j,INF); } } for (int i=1;i<=n;i++) { that_edge[i]=e_max; add_edge(i,i+n,1); } int temp=max_flow(s,t); bool first=false; printf("%d\n",temp); for (int i=1;i<=n && temp;i++) { if (i==s-n || i==t) continue; if (!flow[that_edge[i]]) continue;//最小割邊一定滿流,考慮逆否命題,不滿流的邊一定不是最小割邊 cap[that_edge[i]]=0; int k=max_flow(s,t); if (k<temp) { if (first) putchar(' '); first=true; printf("%d",i); } else cap[that_edge[i]]=1; temp=k; } putchar('\n'); return 0;}