HDU3718/ZOJ3425 Similarity(The 2010 ACM-ICPC Asia Chengdu Regional Contest,加权二分图的最优匹配)

来源:互联网 发布:mysql 修改字段属性 编辑:程序博客网 时间:2024/05/22 08:49

只要能看出来是二分图的最优匹配,然后建图,套模板,应该就能过了,几乎是裸模板题,听 亚伟 说去年现场赛的时候小伟他们1Y过掉这个题,然后就尝试了下,的确不是很难,这又给了我们弱小心灵一点点希望和安慰……

我用的是 KM算法 ,调整顶标值加上一直 dfs 找增广路(就是二分图最大匹配的匈牙利算法),具体解释参见:

http://hi.baidu.com/wwbmmm/blog/item/7f356cfa92d23962034f56e5.html

PS:不要光看博文,下面有个牛牛的评论,相当给力!!!

我的代码:

#include<cstdio>#include<iostream>#include<cstring>#include<climits>#define min(a,b) a<b?a:b#define max(a,b) a>b?a:bconst int N = 30;struct point{char name;int id;};point pa[N],pb[N];int map[N][N],len,g,stu;void addpoint_a(char x,int &k1){//构造二分图的x点集int i,add=1;for(i=1;i<k1;i++){if(x==pa[i].name){add=0;break;}}if(add){pa[k1].name=x;pa[k1].id=k1;k1++;}}void addpoint_b(char x,int &k2){//构造二分图的y点集int i,add=1;for(i=1;i<k2;i++){if(x==pb[i].name){add=0;break;}}if(add){pb[k2].name=x;pb[k2].id=k2;k2++;}}int searchx(char x,point p[]){for(int i=1;i<=g;i++){if(p[i].name==x)return p[i].id;}return -1;}int lx[N],ly[N],match[N],visx[N],visy[N],lack;int dfs(int x){//匈牙利visx[x]=1;for(int i=1;i<=g;i++){if(!visy[i] && lx[x]+ly[i]==map[x][i]){visy[i]=1;if(match[i]==-1 || dfs(match[i])){match[i]=x;return 1;}}}return 0;}int KM(){int i,j,k;for(i=1;i<=g;i++){//初始化顶标lx[i]=INT_MIN; ly[i]=0;for(j=1;j<=g;j++)lx[i]=max(map[i][j],lx[i]);}memset(match,-1,sizeof(match));for(i=1;i<=g;i++){while(1){//直到每个点都成功匹配,才结束循环memset(visx,0,sizeof(visx));memset(visy,0,sizeof(visy));if(dfs(i))break; //如果点 i 成功匹配,则不需要调整定标值/*------------顶标调整------------*/int lack=INT_MAX;//顶标调整值for(j=1;j<=g;j++){if(visx[j]){for(k=1;k<=g;k++){//取幅度最小的值为调整值if(!visy[k])lack=min(lx[j]+ly[k]-map[j][k],lack);}}}for(j=1;j<=g;j++){//调整已经得到匹配的点对的顶标值if(visx[j])lx[j]-=lack;if(visy[j])ly[j]+=lack;}/*---------------------------------*/}}int sum=0;for(i=1;i<=g;i++){if(match[i]!=-1)sum+=map[match[i]][i];}return sum;}void solve(){int i,j;char str[10010],ch[3];scanf("%d%d%d",&len,&g,&stu);int k1=1;for(i=1;i<=len;i++){scanf("%s",ch);str[i]=ch[0];addpoint_a(str[i],k1);}for(i=0;i<stu;i++){int k2=1;memset(map,0,sizeof(map));memset(pb,0,sizeof(pb));for(j=1;j<=len;j++){scanf("%s",ch);addpoint_b(ch[0],k2);int a=searchx(str[j],pa);int b=searchx(ch[0],pb);map[a][b]++;}int ans=KM();printf("%.4lf\n",ans*1.0/len);}}int main(){int t;scanf("%d",&t);while(t--){solve();}return 0;}


原创粉丝点击