http://acm.hdu.edu.cn/showproblem.php?pid=2426
题意:
每n个学生和m个房间,现在要为每个学生安排一个房间居住,每个学生对于一些房间有一些满意度,如果满意度为负就说明该学生不喜欢住在这房间。现在问如何安排可以使所有学生的满意度总和最大。(不能将学生安排到他不喜欢的房间或者他没有评价的房间)
思路:
二分图的最佳匹配,注意题目的要求即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn = 500+5; 6 const int INF = 0x3f3f3f3f; 7 8 int n, m, k; 9 int g[maxn][maxn]; 10 int lx[maxn], ly[maxn]; 11 bool S[maxn], T[maxn]; //记录左右两边节点是否已匹配 12 int match[maxn]; 13 int slack[maxn]; //差值 14 15 bool dfs(int i) 16 { 17 S[i] = true; 18 for (int j = 1; j <= m; ++j) 19 { 20 if (T[j]) continue; //每一轮匹配,右边节点只能一次 21 int gap = lx[i] + ly[j] - g[i][j]; 22 if (gap == 0) //如果符合要求 23 { 24 T[j] = true; 25 if (match[j] == -1 || dfs( match[j] )) 26 { 27 match[j] = i; 28 return true; 29 } 30 } 31 else slack[j] = min(slack[j], gap); 32 } 33 return false; 34 } 35 36 int KM() 37 { 38 memset(match, -1, sizeof match); 39 memset(ly, 0, sizeof ly); //初始化ly为0 40 for (int i = 1; i<=n; i++) //初始化lx[i]为该节点所有边中的最大权值 41 { 42 lx[i] = g[i][1]; 43 for (int j = 2; j<=m; j++) 44 lx[i] = max(lx[i], g[i][j]); 45 } 46 for (int i=1; i<=n; i++) //尝试为每个节点匹配节点 47 { 48 memset(slack,INF,sizeof(slack)); //因为要取最小值,初始化为无穷大 49 while (true) { 50 memset(S, false, sizeof S); //记录每轮匹配中左右节点是否被尝试匹配过 51 memset(T, false, sizeof T); 52 if (dfs(i)) break; 53 int d = INF; 54 for (int j=1; j<=m; j++) 55 if (!T[j]) d = min(d, slack[j]); 56 for (int j=1; j<=n; ++j) 57 if (S[j]) lx[j] -= d; 58 for(int j=1;j<=m;j++) 59 { 60 if (T[j]) ly[j] += d; 61 else slack[j] -= d; 62 } 63 } 64 } 65 66 int result = 0,flag=0; 67 for(int i = 1; i <=m; i++){ 68 if(match[i]==-1||g[match[i]][i]==-INF) 69 continue; 70 if(match[i]>-1){ 71 result += g[match[i]][i]; 72 flag++; 73 } 74 } 75 if(flag<n) result=-1; 76 return result; 77 78 } 79 80 int main() 81 { 82 //freopen("in.txt","r",stdin); 83 int cas = 0; 84 while(~scanf("%d%d%d",&n,&m,&k)) 85 { 86 if(n>m) 87 { 88 printf("Case %d: %d\n", ++cas, -1); 89 continue; 90 } 91 for(int i=1;i<=n;i++) 92 for(int j=1;j<=m;j++) 93 g[i][j] = -INF; 94 for(int i=0;i<k;i++) 95 { 96 int u,v,w; 97 scanf("%d%d%d",&u,&v,&w); 98 u++; v++; 99 if(w>=0) g[u][v] = w; 100 } 101 int ans = KM(); 102 printf("Case %d: %d\n", ++cas, ans); 103 } 104 return 0; 105 }