HDU -- 2853 Assignment 【思维 + KM算法】

来源:互联网 发布:交互动画软件 编辑:程序博客网 时间:2024/06/05 18:58

传送门

//题意:尽量在保证之前的匹配的情况下使得最优匹配.
分析样例:
对应第一组:
2 1 3
3 2 4
1 26 2
显然有两种匹配方式能够达到最优匹配(32):
①第一行第三个,第二行第一个,第三行第二个。不相似的个数:2
②第一行第一个,第二行第三个,第三行第二个。不相似的个数:3
那么尽量更小的一样,那么输出2 32-原匹配(6) 2 26;

//思路: 分析了后你可能知道为什么直接去找最优的可能是不对的了, 因为加入一家公司在2,3任务的权值都是最大的且相同, 而题目给的原匹配是做3任务, 而直接去找最优的可能会找到2任务, 导致答案错误. 所以我们可以再尽可能保证源匹配下去找最优匹配. 方法就是让每一个原先的值乘一个数(假如是100) 则让题目给的那个任务再加个1, 这样既保证了在同等条件下, 尽量去找的题目给的匹配, 并且也不会影响比这个更优的选择.

AC Code

const int maxn=100+5;int g[maxn][maxn];int link[maxn],lx[maxn],ly[maxn];bool visx[maxn],visy[maxn];int a[maxn];int nx,ny,d;bool Find(int x){    visx[x] = true;    for(int i=1;i<=ny;i++){        if(visy[i]) continue;        int tmp = lx[x] + ly[i] - g[x][i];        if(!tmp){            visy[i] = true;            if(link[i] == -1 || Find(link[i])){                link[i] = x;                return true;            }        }        else d=min(d,tmp);    }    return false;}int KM(){    Fill(link,-1);    Fill(ly,0); Fill(lx,0);    for(int i=1;i<=nx;i++){        for(int j=1;j<=ny;j++){            if(g[i][j] > lx[i])                lx[i] = g[i][j];        }    }    for(int i =1 ; i<= nx;i++){        while(true){            Fill(visx,false);            Fill(visy,false);            d = inf;            if(Find(i)) break;            for(int j = 1 ; j<=nx ; j++)                if(visx[j]) lx[j] -= d;            for(int j = 1 ; j<=ny ; j++)                if(visy[j]) ly[j] += d;        }    }    int ans = 0;    for(int i=1;i<=ny;i++){        if(link[i] == -1) continue;        ans += g[link[i]][i];    }//如果选择的还是题目的给的匹配则%100后就是1, 而不是的%100后都是0,所以新匹配的个数是nx-ans%100.    printf("%d ",nx-ans%100);    return ans;}void solve(){    while(~scanf("%d%d",&nx,&ny)){        Fill(g,0); Fill(a,-1);        for(int i=1;i<=nx;i++){            for(int j=1;j<=ny;j++){                scanf("%d",&g[i][j]);                g[i][j] *= 100;            }        }        int res2 = 0;        for(int i=1;i<=nx;i++){            int u;            scanf("%d",&u);            res2 += g[i][u];            g[i][u]++;  //让原匹配大一点.        }        int res = KM();        printf("%d\n",(res-res2)/100);    }}
原创粉丝点击