Friendship

这题求得是点连通度,或最小割点集。删除这个集合,S到T就不连通,删除这个集合的任意真子集,S到T仍然有路可走。

做法是拆点,将每个人p拆成两个点p和p',令p' = p + N, 建边<p', p, 1>,1为容量,其余的,如果A有B的号码,建边<A,B',INF>,最后求出S到T'的最大流即可(不同的建边情况不同,这里是S到T')。

还有一难点是如果有多组解,输出score最小的一个,其实就是输出字典序最小的一个。按升序枚举,这个每次删除一个点,删除后,如果流量减少,即为最小割割点,记录一下,如果没有减少,则恢复这个点。当然,如果S和T直接相连,输出NO ANSWER!。

代码
#include<stdio.h>
#include
<string.h>
#define INF 0x3fffffff
#define MM 15004
#define NN 404
typedef
struct node{
int v, c;
struct node *nxt, *op;
}NODE;

NODE edg[MM];
NODE
*Link[NN];

int idx, n, S, T, N;
int h[NN];
int num[NN];
int mark[NN];
int flag[NN][NN];
void Add(int u, int v, int c1, int c2){
idx
++;
edg[idx].v
= v;
edg[idx].c
= c1;
edg[idx].nxt
= Link[u];
edg[idx].op
= edg + idx + 1;
Link[u]
= edg + idx;
idx
++;
edg[idx].v
= u;
edg[idx].c
= c2;
edg[idx].nxt
= Link[v];
edg[idx].op
= edg + idx - 1;
Link[v]
= edg + idx;
}

int aug(int u, int flow){
int f;
int l = flow;
int tmp = n - 1;
if (u == T + N) return flow;
for (NODE *p = Link[u]; p; p = p->nxt){
if (p->c && h[u] == h[p->v] + 1){
f
= aug(p->v, p->c < l ? p->c : l);
l
-= f;
p
->c -= f;
p
->op->c += f;
if (!l || h[S] == n) return flow - l;
}
if (p->c && h[p->v] < tmp) tmp = h[p->v];
}
if (l == flow){
if (!--num[h[u]]) h[S] = n;
else ++num[h[u] = tmp + 1];
}
return flow - l;
}
int Sap(){
int ans = 0;
n
= 2 * N;
memset(h,
0, sizeof(h));
memset(num,
0, sizeof(num));
num[
0] = n;
while(h[S] < n){
ans
+= aug(S, INF);
}
return ans;
}
void CreatGraph(){
int i, j, ii;
idx
= 0;
memset(Link,
0, sizeof(Link));
for (i = 1; i <= N; i++){
if (mark[i]) continue;
for (j = 1; j <= N; j++){
if (mark[j]) continue;
if (i != j && flag[i][j]){
ii
= i + N;
Add(j, ii, INF,
0);
}
}
}
for (i = 1; i <= N; i++){
if (mark[i]) continue;
ii
= i + N;
Add(ii, i,
1, 0);
}
}
int main()
{
int i, j, ans, tmp, t, first;
scanf(
"%d%d%d", &N, &S, &T);
for (i = 1; i <= N; i++){
for (j = 1; j <= N; j++){
scanf(
"%d", &flag[i][j]);
}
}
if(flag[S][T] == 1){
puts(
"NO ANSWER!");
return 0;
}
memset(mark,
0, sizeof(mark));
CreatGraph();
ans
= Sap();
tmp
= ans;
if (ans == 0){
puts(
"0");
return 0;
}
for (i = 1; i <= N; i++){
if(i == S || i == T) continue;
mark[i]
= 1;
CreatGraph();
t
= Sap();
if (t < tmp){
tmp
= t;
}
else{
mark[i]
= 0;
}
}
printf(
"%d\n", ans);
first
= 1;
for (i = 1; i <= N; i++){
if(mark[i])
if(first){
first
= 0;
printf(
"%d", i);
}
else printf(" %d", i);
}
puts(
"");
return 0;
}

 

posted on 2010-08-15 21:47  ylfdrib  阅读(625)  评论(0编辑  收藏  举报