程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 1815 Friendship 求最小點割集

POJ 1815 Friendship 求最小點割集

編輯:C++入門知識

點擊打開鏈接 Friendship Time Limit: 2000MS Memory Limit: 20000K Total Submissions: 8747 Accepted: 2451 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 3 1 1 0 1 1 1 0 1 1 Sample Output   1 2 Source   POJ Monthly   給你一個圖,要求至少刪除圖中幾個點,使得起點到終點不連通。如果有多種方案,輸出序號最下的那種。 最小點割集:無向(有向)圖G中,給定源點s和終點t,至少要刪去多少個點(具體一點,刪哪些點),使得s和t不連通。 解法:一般最小點割轉化到最小邊割上,將原圖中的點v拆成v'和v'',且w(v‘,v'')=1。對於原圖中的有向邊(u,v),則有w(u'',v')=INF;若是無向邊,則還要加上邊:w(v',u'')=INF。然後求以s''為源點,t'為匯點的最大流。maxflow即為最少需要刪的點數,割邊集對應了具體刪的點的一組解。 題目要求輸出序號最小的,我們可以按照序號從小到大枚舉每一個點,然後刪除i'和i'',如果新的最大流比原來的最大流小,說明這個點在最小割裡面,否則回復刪除的邊。 [cpp]   //1408K 704MS   #include<stdio.h>   #include<string.h>   #include<algorithm>   #define inf 0x3f3f3f3f   #define M 1007   #define MIN(a,b) a>b?b:a;   using namespace std;   struct E   {       int v,w,next;   } edg[500000];   int dis[M],gap[M],head[M],nodes;   int sourse,sink,nn;   int g[M][M],cut[M],p[M];   int n;   void addedge(int u,int v,int w)   {       edg[nodes].v=v;       edg[nodes].w=w;       edg[nodes].next=head[u];       head[u]=nodes++;       edg[nodes].v=u;       edg[nodes].w=0;       edg[nodes].next=head[v];       head[v]=nodes++;   }   int dfs(int src,int aug)   {       if(src==sink)return aug;       int left=aug,mindis=nn;       for(int j=head[src]; j!=-1; j=edg[j].next)       {           int v=edg[j].v;           if(edg[j].w)           {               if(dis[v]+1==dis[src])               {                   int minn=MIN(left,edg[j].w);                   minn=dfs(v,minn);                   edg[j].w-=minn;                   edg[j^1].w+=minn;                   left-=minn;                   if(dis[sourse]>=nn)return aug-left;                   if(left==0)break;               }               if(dis[v]<mindis)                   mindis=dis[v];           }       }          if(left==aug)       {           if(!(--gap[dis[src]]))dis[sourse]=nn;           dis[src]=mindis+1;           gap[dis[src]]++;       }       return aug-left;   }   int sap(int s,int e)   {       int ans=0;       nn=n*2;       memset(dis,0,sizeof(dis));       memset(gap,0,sizeof(gap));       gap[0]=nn;       sourse=s;       sink=e;       while(dis[sourse]<nn)           ans+=dfs(sourse,inf);       return ans;   }   void build()   {       memset(head,-1,sizeof(head));       nodes=0;       for(int i=1;i<=n;i++)           for(int j=1;j<=n;j++)            if(g[i][j]){addedge(i+n,j,inf);addedge(j+n,i,inf);}       for(int i=1; i<=n; i++)           if(!cut[i])addedge(i,i+n,1);           else addedge(i,i+n,0);   }   int main()   {       int start,end;       scanf("%d%d%d",&n,&start,&end);       memset(head,-1,sizeof(head));       memset(cut,0,sizeof(cut));       nodes=0;       for(int i=1; i<=n; i++)           for(int j=1; j<=n; j++)               scanf("%d",&g[i][j]);       if(g[start][end])       {           printf("NO ANSWER!\n");           return 0;       }       build();//建圖       int anss=sap(start+n,end);       printf("%d\n",anss);       int cnt=0;       for(int i=1; i<=n&&anss; i++)       {           if(i==start||i==end)continue;           cut[i]=1;           build();           if(sap(start+n,end)==anss-1)           {               anss--;               p[cnt++]=i;           }           else  cut[i]=0;       }       for(int i=0; i<cnt; i++)           printf("%d ",p[i]);       printf("\n");       return 0;   }    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved