这个题目纠结的我要死。。。
首先是最大流的第一次应用, 我一直认为是求最大流那错了。。。
事实上,那里确实出错了一次。。。不过,那也无关紧要,主要是对那个字符串的处理,即将题目给的输入转化成一个图。
这个过程,我仍然没有完全的清楚。所以导致了卡的太久。。。
这个题,开始我自己想的时候,是想到了二分图,其实二分图,也差不多。
最主要,最关键的还是建图。。。这个图你转化不过来的话,没搞手,,
所以我觉得这个题,要分析的透彻了之后再动手打代码。。 不然你真的会付出代价的。。
这个透彻是要全部理解了。。。
首先,理解由多源点多汇点图,转化成单源单汇图。 N=(V,X,Y,A,C) ==> N=(V,s,t,A,C)。源点都在X集合里,汇点都在Y集合里。这样的一个S(X,Y)称为N的一个割。
建立 s到X 集合里所有点的边 和 Y集合里的点到 t 的所有边。边上的权值等下说。
s,t 称为人工源和人工汇,这个我们可以自己设置。
到这里我们要将图建成功的话,就必须要知道X,Y这两个集合,以及X,Y两个集合之间的边。
先来建立Y集合。
Y集合的话也就是房间里的各个插座,将每个插座按输入的顺序标上序号。然后连上汇点 t。 边权都为1 。 因为近来一个就说明有一个被用了。最多也就那么多个。所以都是1
X集合就是每个用电器的插座的名字,接着上面的序号按照输入顺序标号,这里要注意,假如某个用电器的插头是房间里有的,就直接用上面的已经标了的序号。 如果房间里没有对应的插座,那么就接着上面的序号按照输入的顺序标号,然后让s 与这些用电器的插头的序号 连接上,边权值就是这个插头出现的次数。
最后就是X, Y 集合之间的边了。。
假如在名字和上面出现的有相同的,那么就用那个插头的序号。否则,继续接着上面的那个序号按输入顺序标号。然后将两个点连接起来,边权设为无穷大
到此为止,图建好了。
然后直接求最大流就可以了。 几乎是一道最大流的模板题。
下面贴代码:
Source Code Problem: 1087 User: 201141919106 Memory: 344K Time: 0MS Language: C Result: Accepted Source Code #include <stdio.h> #include <stdlib.h> #include<string.h> #define N 403 #define Z N #define INF 0x7fffffff int V[N]; int d[N]; int next[N*3]; int cap[N*3]; int path[N]; int E[N*3]; int S,T,M; void init(int from,int to,int c) { M++; cap[M]=c; E[M]=to; next[M]=V[from]; V[from]=M; } void insert(int from,int to,int c) { init(from,to,c); init(to,from,0); } int bfs() { int queue[N]; int f,t; int x,i,y; f=t=0; memset(d,0,sizeof(d)); queue[t++]=S; d[S]=1; while(f!=t) { x=queue[f++]; for(i=V[x]; i; i=next[i]) { y=E[i]; if(cap[i]>0&&d[y]==0) { d[y]=d[x]+1; if(y==T) { return 1; } queue[t++]=y; } } } return 0; } int dfs() { int i,t,back,u,y; int maxFlow=0; int min; t=1; while(t) { u=(t==1)?S:E[path[t-1]]; if(u==T) { min=INF; for(i=1; i<t; i++) { if(cap[path[i]]<min) { min=cap[path[i]]; back=i; } } for(i=1; i<t; i++) { cap[path[i]]-=min; cap[path[i]+1]+=min; } maxFlow+=min; t=back; } else { for(i=V[u]; i; i=next[i]) { y=E[i]; if(cap[i]>0&&(d[y]==d[u]+1))break; } if(i) { path[t++]=i; } else { d[u]=0; t--; } } } return maxFlow; } int dinic() { int maxFlow=0; while(bfs()) { maxFlow+=dfs(); } return maxFlow; } int main() { int n,m,j,q,r,i,c; char s[Z][Z],str[Z],ch[Z]; int p[Z]; while(~scanf("%d\n",&n)) { M=0; S=0; T=N-1; memset(V,0,sizeof(V)); memset(p,0,sizeof(p)); memset(E,0,sizeof(E)); memset(cap,0,sizeof(cap)); memset(next,0,sizeof(next)); memset(s,0,sizeof(s)); memset(str,0,sizeof(str)); memset(ch,0,sizeof(ch)); for(i=1; i<=n; i++) { scanf("%s",s[i]); insert(i,T,1); } c=n; scanf("%d\n",&m); for(i=0; i<m; i++) { scanf("%s %s",str,ch); for(j=1; j<=c; j++) { if(strcmp(s[j],ch)==0) { p[j]++; break; } } if(j>c) { strcpy(s[++c],ch); p[c]++; } } scanf("%d\n",&r); for(i=1; i<=r; i++) { scanf("%s%s",str,ch); for(j=1; j<=c; j++) { if(strcmp(s[j],str)==0) { break; } } if(j>c) { strcpy(s[++c],str); } for(q=1; q<=c; q++) { if(strcmp(s[q],ch)==0) { break; } } if(q>c) { strcpy(s[++c],ch); } insert(j,q,INF); } for(i=1; i<=c; i++) { insert(S,i,p[i]); } printf("%d\n",m-dinic()); } return 0; }