Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2829 Accepted Submission(s): 1423
#include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #define N 110 #define INF 99999999 int n, m; char map[N][N]; //存储原始字符地图的 int ma[N][N]; //类似边表的可匹配存储 int lx[N], ly[N]; int vtx[N], vty[N]; int match[N]; int slack[N]; int cnt; int max(int a, int b) { return a>b?a:b; } int min(int a, int b) { return a>b?b:a; } int hungary(int dd) //匈牙利算法 { int i; vtx[dd]=1; for(i=0; i<cnt; i++) { if(vty[i]) continue; else { if(lx[dd]+ly[i] == ma[dd][i] ) { vty[i]=1; if(match[i]==-1 || hungary(match[i]) ) { match[i] = dd; return 1; } } else slack[i] = min( slack[i], lx[dd] + ly[i]-ma[dd][i] ); } } return 0; } void km_match() //最大权匹配 { int i, j; int temp; memset(lx, 0, sizeof(lx)); memset(ly, 0, sizeof(ly)); for(i=0; i<cnt; i++) { for(j=0; j<cnt; j++) { lx[i]=max(lx[i], ma[i][j] ); } //表示当前的i号人,去某一个房子的最大距离 } for(i=0; i<cnt; i++) { for(j=0; j<cnt; j++) { slack[j]=INF; //初始无穷大 } while(1) { memset(vtx, 0, sizeof(vtx)); memset(vty, 0, sizeof(vty)); if(hungary(i)) //匈牙利算法 break; else { temp=INF; for(j=0; j<cnt; j++) { if(!vty[j]) { temp=min(temp, slack[j] ); } } for( j=0; j<cnt; j++ ) { if( vtx[j] ) lx[j] -= temp; if( vty[j] ) ly[j] += temp; else slack[j] -= temp; } } } } } int main() { int i, j, k, ll; int ci, cj; int sum; while(scanf("%d %d", &n, &m) && n!=0 && m!=0 ) { memset(match, -1, sizeof(match ));//match数组初始 -1,记录父节点 cnt=0; for(i=0; i<n; i++ ) { scanf("%*c"); //每行先取一个回车换行 for(j=0; j<m; j++) { scanf("%c", & map[i][j] ); if(map[i][j] == 'm' ) //如果是个人 { cnt++; //记录 人数, 建图时需要 } } } //四层循环 前两层遍历map寻找m 内两层循环找h ci=0; cj=0; for(i=0; i<n; i++) { for(j=0; j<m; j++) { if(map[i][j]=='m') //找到一个人 { //找到人之后遍历map找 H for(k=0; k<n; k++) { for(ll=0; ll<m; ll++) { if(map[k][ll]=='H') { ma[ci][cj++] = 100-(abs(k-i)+abs(ll-j)); //大数减边 } } } ci++; //换到下一行存储 cj=0; //cj指针回到0位置 } } } km_match(); //最大权匹配 sum=0; for(i=0; i<cnt; i++) { sum+=ma[match[i]][i] ; } printf("%d\n", 100*cnt-sum ); } return 0; }
#include<iostream> #include<cstring> #include<climits> #include<cstdio> #include<algorithm> #define N 110 using namespace std; char maps[N][N]; //存储原始字符地图的 int map[N][N]; //类似边表的可匹配存储 int lx[N], ly[N]; int slack[N]; int match[N]; bool visitx[N], visity[N]; int n; bool Hungary( int u ) //匹配 { int i ; visitx[u] = true; for( i=0; i < n; ++i) { if(visity[i]==true ) continue; else { if(lx[u] + ly[i] == map[u][i] ) { visity[i] = true; if(match[i] == -1 || Hungary(match[i]) ) { match[i] = u; return true; } } else slack[i] = min(slack[i], lx[u] + ly[i]-map[u][i] ); } } return false; } void KM_perfect_match() //匈牙利算法 { int temp; memset(lx, 0, sizeof(lx)); // 清零?? memset(ly, 0, sizeof(ly)); // 清零?? for(int i=0; i<n; ++i) for(int j=0; j<n; ++j) lx[i] = max( lx[i], map[i][j] ); //表示当前的i号人,去某一个房子的最大距离 for(int i=0; i<n; ++i) { /* 我们给每个Y顶点一个“松弛量”函数slack,每次开始找增广路时初始化为无穷大。 在寻找增广路的过程中,检查边(i,j)时,如果它不在相等子图中,则让slack[j]变成 原值与A[i]+B[j]-w[i,j]的较小值。 这样,在修改顶标时,取所有不在交错树中的Y顶点的slack值中的最小值作为d值即可。 但还要注意一点:修改顶标后,要把所有的不在交错树中的Y顶点的slack值都减去d。 */ for(int j=0; j<n; ++j) slack[j] = INT_MAX; while(1) { memset(visitx, false, sizeof(visitx)); //清零 memset(visity, false, sizeof(visity)); //清零 if( Hungary(i) ) break; else { temp = INT_MAX; for(int j=0; j<n; ++j ) { if(!visity[j]) { temp = min(temp, slack[j]); } } for(int j=0; j<n; ++j ) { if( visitx[j] ) lx[j] -= temp; if( visity[j] ) ly[j] += temp; else slack[j] -= temp; } } } } } int main() { int row, col, ans, numi, numj; while(scanf("%d %d", &row, &col) && (row + col) ) //行 列 { n = ans = numi = numj = 0; memset(match, -1, sizeof(match)); //match数组初始 -1 for(int i=0; i<row; ++i) { scanf("%*c");//取回车 for(int j=0; j<col; ++j) { scanf("%c", &maps[i][j]); if(maps[i][j] == 'm') n++; //记录 人数 } } //果然是四层循环啊,和预想的一样 for(int i=0; i<row; ++i) //建图 { for(int j=0; j<col; ++j) { //如果当前的是: 人 if(maps[i][j] == 'm') { //暴力一遍整个map, for(int k=0; k<row; ++k ) { for(int l = 0; l < col; ++l) { if(maps[k][l] == 'H') // 如果当前找到了一所房子 { //建图时的特殊处理(类似入栈, 不过这次入得是二维数组 map[numi][numj++] = 100 - (abs(k - i) + abs(l - j)); //大数减边 } //等同于给每个人开了一个一位数组 } } numi++ ; //当找到下一个人的时候, 二维数组挪到下一行 numj = 0 ; //位置指针归零 } } } KM_perfect_match(); //调用匈牙利算法 for(int i = 0; i < n; ++i ) { ans = ans + map[match[i]][i]; } printf("%d\n", 100 * n - ans) ; } return 0; } ///////////////