大致题意:
吕布要跟曹操pk。吕布有n个小弟,曹操有m个。已知可以由k种打架的方式,每种方式都是一个吕布的小弟去虐另一个曹操的人,每种方式都有一个伤害值。而且吕布和曹操的人都只能干一架。求伤害值最少是多少。
大致思路:
二分图最小权匹配。初始值全部取负,求出最大匹配后再将这个值取负得到的就是答案。切记tire申请空间不要太给力,被MLE到shi了。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int nMax=404; const int mMax=1005; const int inf=1<<29; int map[nMax][nMax]; int lx[nMax],ly[nMax]; int mapch[nMax]; int stack[nMax]; bool sy[nMax],sx[nMax]; int n,m,e,cnt; int find (int u){ int v,t; sx[u]=1; for(v=1;v<=m;v++){ if(sy[v]) continue; t=lx[u]+ly[v]-map[u][v]; if(t==0){ sy[v]=1; if(mapch[v]==-1||find(mapch[v])){ mapch[v]=u; return 1; } } else if(t<stack[v]) stack[v]=t; } return 0; } int KM(){ int i,j,k,d,sum=0; cnt=0; for(i=1;i<=m;i++) ly[i]=0; memset(mapch,-1,sizeof(mapch)); for(i=1;i<=n;i++){ lx[i]=-inf; for(j=1;j<=m;j++) if(map[i][j]>lx[i]) lx[i]=map[i][j]; } for(i=1;i<=n;i++){ for(j=1;j<=m;j++) stack[j]=inf; while(1){ for(k=1;k<=m;k++) sy[k]=0; for(k=1;k<=n;k++) sx[k]=0; if(find(i)) break; d=inf; for(k=1;k<=m;k++) if(!sy[k]&&stack[k]<d) d=stack[k]; for(k=1;k<=n;k++) if(sx[k]) lx[k]-=d; for(k=1;k<=m;k++) if(sy[k]) ly[k]+=d; else stack[k]-=d; } } for(i=1;i<=m;i++) if(mapch[i]!=-1&&map[mapch[i]][i]!=-inf){ sum+=map[mapch[i]][i]; } return sum; } class nodea{ public: int id; nodea *p[65]; nodea(){ int i; id=-1; for(i=0;i<65;i++)p[i]=NULL; } }; nodea *root; int cnt1,cnt2; int getnum(char *s,int &cc){ int i; nodea *r=root; int l=strlen(s); for(i=0;i<l;i++){ if(r->p[s[i]-60]==NULL){ r->p[s[i]-60]=new nodea(); } r=r->p[s[i]-60]; } if(r->id==-1){ r->id=cc; cc++; } return r->id; } int main(){ int i,j,k,s,a,b; char name1[30],name2[30]; while(scanf("%d%d%d",&n,&m,&k)!=EOF){ cnt1=cnt2=1; root=new nodea(); for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ map[i][j]=-inf; } } while(k--){ scanf("%s%s%d",name1,name2,&s); a=getnum(name1,cnt1); b=getnum(name2,cnt2); map[a][b]=-s; } printf("%d\n",-KM()); } return 0; }