标签:
Time Limit: 2000MS | Memory Limit: 20000KB | 64bit IO Format: %I64d & %I64u |
Description
Input
Output
Sample Input
3 1 3 1 1 0 1 1 1 0 1 1
Sample Output
1 2
n个人,n*n的矩阵表示每个人之间的关系,1表示认识,0表示不认识,现在要删除最少的点,使得S还有H不认识,输出字典序最小的方案
一个比较普通的最小割点集,建图之后,我们每次最大流求出的最大流都是最小割的费用,枚举每一个可以删除的点,如果说删除这个点之后最大流返回值减小,说明这个点删除是有意义的,我们就把他加入删点数组中,进行下一次遍历,如果S已经达不到H,说明最小割目的已经实现
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define MAXN 600 #define MAXM 1000000 #define INF 0x3f3f3f3f int n,S,H,cnt; int vis[MAXN],dis[MAXN],cur[MAXN],head[MAXN],rec[MAXN]; int map[MAXN][MAXN],temp[MAXN][MAXN]; struct node { int u,v,cap,flow,next; }edge[MAXM]; void add(int a,int b,int c) { node E={a,b,c,0,head[a]}; edge[cnt]=E; head[a]=cnt++; node E1={a,b,0,0,head[b]}; edge[cnt]=E1; head[b]=cnt++; } bool BFS(int s,int t) { queue<int>q; memset(vis,0,sizeof(vis)); memset(dis,-1,sizeof(dis)); q.push(s); vis[s]=1; dis[s]=0; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { node E=edge[i]; if(E.cap>E.flow&&!vis[E.v]) { vis[E.v]=1; dis[E.v]=dis[E.u]+1; if(E.v==t) return true; q.push(E.v); } } } return false; } int DFS(int x,int a,int t) { if(a==0||x==t) return a; int flow=0,f; for(int &i=cur[x];i!=-1;i=edge[i].next) { node &E=edge[i]; if(dis[x]+1==dis[E.v]&&(f=DFS(E.v,min(E.cap-E.flow,a),t))>0) { a-=f; flow+=f; edge[i].flow+=f; edge[i^1].flow-=f; if(a==0) break; } } return flow; } int MAXflow(int s,int t) { int flow=0; while(BFS(s,t)) { memcpy(cur,head,sizeof(head)); flow+=DFS(s,INF,t); } return flow; } void getmap() { cnt=0; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++)//最小割建图 { for(int j=1;j<=n;j++) { if(map[i][j]) { if(i==j) { if(i==S||i==H) add(i,i+n,INF); else add(i,i+n,1); } else add(i+n,j,INF); } } } } int main() { while(scanf("%d%d%d",&n,&S,&H)!=EOF) { memset(map,0,sizeof(map)); memset(head,-1,sizeof(head)); cnt=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&map[i][j]); } } getmap(); if(map[S][H]) { printf("NO ANSWER!\n"); continue; } int ans=MAXflow(S,H+n); if(ans==0) { printf("0\n"); continue; } int top=0; for(int i=1;i<=n;i++) { if(i==S||i==H) continue; for(int j=1;j<=n;j++)//枚举每一个可以删除的点 { temp[i][j]=map[i][j]; temp[j][i]=map[j][i]; map[i][j]=map[j][i]=0; } getmap(); int t=MAXflow(S,H+n); if(t<ans)//如果删点之后费用减小 rec[top++]=i,ans=t; else { for(int j=1;j<=n;j++) { map[i][j]=temp[i][j]; map[j][i]=temp[j][i];//如果没有减小,回复 } } } printf("%d\n",top); for(int i=0;i<top;i++) { if(i) printf(" "); printf("%d",rec[i]); } printf("\n"); } return 0; }
poj--1815--Friendship(最小割点集)(枚举求最小字典序)
标签:
原文地址:http://blog.csdn.net/qq_29963431/article/details/51355602