普通EK算法
#include <cstdio> #include <string.h> #include <string> #include <map> #include <iostream> #define min(a,b) ((a)>(b))?(b):(a) using namespace std ; const int maxn=30; const int Inf=0x7fffffff; int cap[maxn][maxn],flow[maxn][maxn],p[maxn],minflow[maxn],q[maxn]; int deg[maxn]; int n,m,junc; int I=0; bool vis[maxn]; int maxflow(int s , int t) { int f=0,u,v,rear,head; memset(flow , 0 , sizeof(flow)); while (true) { memset(minflow , 0 , sizeof(minflow)); minflow[s]=Inf; head=0; rear=1; q[head]=s; while (rear>head) { u=q[head];head++; for (v=0 ; v<=t ; ++v) { if(!minflow[v] && cap[u][v]>flow[u][v]) { p[v]=u; q[rear]=v;rear++; minflow[v]=min(minflow[u],cap[u][v]-flow[u][v]); } } } //printf("mint=%d\n",minflow[t]); if(!minflow[t])break; for (u=t ; u!=s ; u=p[u]) { flow[u][p[u]]-=minflow[t]; flow[p[u]][u]+=minflow[t]; } f+=minflow[t]; } return f; } int find (int x) { return p[x]<0?x:p[x]=find(p[x]); } void merge (int a , int b) { int x=find(a); int y=find(b); int tmp; if(x!=y) { tmp=p[x]+p[y]; (p[x]>p[y])?(p[x]=y,p[y]=tmp):(p[y]=x,p[x]=tmp); junc++; } } int main () { int cas,i,j,u,v,d,sum,point; const int s=26; const int t=27; string str; //map<string,int>mapstr; //freopen ("in.txt","r",stdin); //freopen ("out.txt","w",stdout); scanf("%d",&cas); while (cas--) { memset (cap , 0 , sizeof(cap)); memset (deg , 0 , sizeof(deg)); memset (vis , 0 , sizeof(vis)); //mapstr.clear(); point=sum=0; scanf("%d",&m); for (i=0 ; i<26 ; ++i) p[i]=-1; junc=1; for (i=0 ; i<m ; ++i) { cin>>str>>d; //printf("map=%d\n",mapstr[str]); //if(mapstr[str]==0) { int len=str.size(); u=str[0]-'a';v=str[len-1]-'a'; vis[u]=1; vis[v]=1; merge(u,v); if(v!=u) deg[v]++,deg[u]--; if(d)cap[u][v]+=1; //mapstr[str]=i+1; } //printf("u=%d v=%d \n",u,v); } bool flag=true; for (i=0 ; i<26 ; ++i) if(vis[i])point++; if(point!=junc)flag=false; int odd_d=0,start=28,end=28; for (i=0 ; i<26 ; ++i) { if(deg[i]&1) { odd_d++; if(odd_d==1)start=i,deg[i]--; if(odd_d==2)end=i,deg[i]++; //printf("%d %d\n",i,odd_d); } if(odd_d>2)flag=false; if(!flag)break; } if(flag) { if(odd_d==2) cap[start][end]+=1; for (i=0 ; i<26 ; ++i) { //printf("%d ",deg[i]); deg[i]>>=1; if(deg[i]>0)cap[i][t]=deg[i],sum+=deg[i]; if(deg[i]<0)cap[s][i]=-deg[i]; } int ans=maxflow(s,t); //printf("\n%d %d\n%d %d\n",ans,sum,start,end); printf("%d %d\n",junc,point); if(ans==sum)printf("Case %d: Well done!\n",++I); else printf("Case %d: Poor boy!\n",++I); } else printf("Case %d: Poor boy!\n",++I); } return 0; }
达哥的模板改进之后,跑了JOJ第一,嘿嘿
#include <cstdio> #include <string.h> #define min(a,b) ((a)>(b))?(b):(a) using namespace std ; const int maxn=28; const int Inf=0x5fffffff; int cap[maxn][maxn],dist[maxn],gap[maxn],fath[maxn]; int deg[maxn]; int n=27,m,junc; int I=0; const int source=0;//这个模板的汇点好像必须是0,一开始设成26怎么都调不对 const int sink=27; bool vis[maxn]; int dfs (int p , int limit=Inf) { if(p==n)return limit; for (int i=0 ; i<=n ; ++i) { if(dist[p]==dist[i]+1 && cap[p][i]>0) { int t=dfs(i,min(limit , cap[p][i])); if(t<0)return t;//没有增广路了 if(t>0)//更新流 { cap[p][i]-=t; cap[i][p]+=t; return t; } } } int tmp=n+1 ; for (int i=0 ; i<=n ; ++i) if(cap[p][i]>0) tmp=min(tmp,dist[i]+1); //printf("dist[p]=%d dist0=%d tmp=%d\n",dist[p],dist[0],tmp); //printf("gap="); //for (int i=0 ; i<n ; i++)printf("%d ",gap[i]); //puts(""); if(--gap[dist[p]]==0 || dist[0]>n)return -1;//出现断层或回流已满 ++gap[dist[p]=tmp]; return 0; } int SAP() { gap[source]=n+1; int f = 0 , t=0; while (~(t=dfs(source))) f+=t; //printf("%d\n",t); return f; } int find (int x) { return fath[x]<0?x:fath[x]=find(fath[x]); } void merge (int a , int b) { int x=find(a); int y=find(b); int tmp; if(x!=y) { tmp=fath[x]+fath[y]; (fath[x]>fath[y])?(fath[x]=y,fath[y]=tmp):(fath[y]=x,fath[x]=tmp); junc++; } } int main () { int cas,i,j,u,v,d,sum,point; char str[25]; scanf("%d",&cas); while (cas--) { memset (cap , 0 , sizeof(cap)); memset (deg , 0 , sizeof(deg)); memset (vis , 0 , sizeof(vis)); memset (dist , 0 , sizeof(dist)); memset (gap , 0 , sizeof(gap)); point=sum=0; scanf("%d",&m); for (i=1 ; i<=26 ; ++i) fath[i]=-1; junc=1; for (i=0 ; i<m ; ++i) { scanf("%s%d",str,&d); { int len=strlen(str); u=str[0]-'a'+1;v=str[len-1]-'a'+1; vis[u]=1; vis[v]=1; merge(u,v); if(v!=u) deg[v]++,deg[u]--; if(d)cap[u][v]+=1; } //printf("u=%d v=%d \n",u,v); } bool flag=true; for (i=1 ; i<=26 ; ++i) if(vis[i])point++; if(point!=junc)flag=false; int odd_d=0,start=28,end=28; for (i=1 ; i<=26 ; ++i) { if(deg[i]&1) { odd_d++; if(odd_d==1)start=i,deg[i]--; if(odd_d==2)end=i,deg[i]++; } if(odd_d>2)flag=false; if(!flag)break; } if(flag) { if(odd_d==2) cap[start][end]++; for (i=1 ; i<=26 ; ++i) { deg[i]>>=1; if(deg[i]>0)cap[i][sink]=deg[i],sum+=deg[i]; if(deg[i]<0)cap[source][i]=-deg[i]; } int ans=SAP(); if(ans==sum)printf("Case %d: Well done!\n",++I); else printf("Case %d: Poor boy!\n",++I); } else printf("Case %d: Poor boy!\n",++I); } return 0; }