Assignment (HDU 2853 最大权匹配KM)
Assignment
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1068 Accepted Submission(s): 551
We have N companies of troops and M missions, M>=N. One company can get only one mission. One mission can be assigned to only one company. If company i takes mission j, we can get efficiency Eij.
We have a assignment plan already, and now we want to change some companies’ missions to make the total efficiency larger. And also we want to change as less companies as possible.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.
3 3 2 1 3 3 2 4 1 26 2 2 1 3 2 3 1 2 3 1 2 3 1 2
2 26 1 2
题意:n个公司m个任务。每一个公司仅仅接受一个任务。每一个任务仅仅被一个公司接受,每一个公司i接受任务j的做事效率为g[i][j],如今已经分配好了。问如何改变任务分配能够让效率最大,求出要修改的公司数目和添加的效率。
思路:与hdu3315相似,hdu 3315;若点数为N,则把每条边的权值扩大x倍(x>N),若是原有匹配。则再把权值加1。最后KM算法求出ans,则最大权值之和=ans/x。没有被修改的=ans%x。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define maxn 1005 #define MAXN 2005 #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FREE(i,a,b) for(i = a; i >= b; i--) #define FRL(i,a,b) for(i = a; i < b; i++) #define FRLL(i,a,b) for(i = a; i > b; i--) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf printf #define DBG pf("Hi\n") typedef long long ll; using namespace std; /* KM算法 O(nx*nx*ny) 求最大权匹配(最佳匹配) 若求最小权匹配,可将权值取相反数,结果取相反数 点的标号从0開始 */ const int N=110; int nx,ny; //两边的点数 int g[N][N]; //二分图描写叙述,g赋初值为-INF int linker[N],lx[N],ly[N]; //y 中各点匹配状态。x,y中的点的标号 int slack[N]; bool visx[N],visy[N]; bool flag; bool DFS(int x) { visx[x]=true; for (int y=0;y<ny;y++) { if (visy[y]) continue; int tmp=lx[x]+ly[y]-g[x][y]; if (tmp==0) { visy[y]=true; if (linker[y]==-1||DFS(linker[y])) { linker[y]=x; return true; } } else if (slack[y]>tmp) slack[y]=tmp; } return false; } int KM() { flag=true; memset(linker,-1,sizeof(linker)); memset(ly,0,sizeof(ly)); for (int i=0;i<nx;i++) //赋初值。lx置为最大值 { lx[i]=-INF; for (int j=0;j<ny;j++) { if (g[i][j]>lx[i]) lx[i]=g[i][j]; } } for (int x=0;x<nx;x++) { for (int i=0;i<ny;i++) slack[i]=INF; while (true) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if (DFS(x)) break; int d=INF; for (int i=0;i<ny;i++) if (!visy[i]&&d>slack[i]) d=slack[i]; for (int i=0;i<nx;i++) if (visx[i]) lx[i]-=d; for (int i=0;i<ny;i++) { if (visy[i]) ly[i]+=d; else slack[i]-=d; } } } int res=0; for (int i=0;i<ny;i++) { if (linker[i]==-1||g[linker[i]][i]<=-INF) //有的点不能匹配的话return-1 { flag=false; continue; } res+=g[linker[i]][i]; } return res; } //记得nx和ny初始化!!!!
!!
。! int n,m; int main() { #ifndef ONLINE_JUDGE freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin); #endif int i,j,x; while (~sff(n,m)) { nx=n; ny=m; int sum=0; for (i=0;i<n;i++) for (j=0;j<m;j++) { sf(x); g[i][j]=x*100; } for (i=0;i<n;i++) { sf(x);x--; sum+=g[i][x]; g[i][x]++; } int ans=KM(); printf("%d %d\n",n-ans%100,ans/100-sum/100); } return 0; } /* 3 3 2 1 3 3 2 4 1 26 2 2 1 3 2 3 1 2 3 1 2 3 1 2 */