HDU-2255 奔小康赚大钱
2012-01-02 16:17
330 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255
解题思路:
二分图最优匹配的裸题,需要学习一下KM算法。。这道题也可以用网络流做,等学了网络流之后再写一下网络流的解题思路。
本题提供2个版本,一个是最朴素的KM算法,一个是优化后的KM算法(另外使用了输入外挂,成功刷入杭电前三
)
代码如下:
优化版本:
解题思路:
二分图最优匹配的裸题,需要学习一下KM算法。。这道题也可以用网络流做,等学了网络流之后再写一下网络流的解题思路。
本题提供2个版本,一个是最朴素的KM算法,一个是优化后的KM算法(另外使用了输入外挂,成功刷入杭电前三
)
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<climits> #include<algorithm> using namespace std; #define N 310 int map ; bool visitx , visity ; int lx , ly ; int match ; int n; bool Hungary(int u) //匈牙利算法 { visitx[u] = true; for(int i = 0; i < n; ++i) { if(!visity[i] && lx[u] + ly[i] == map[u][i]) { visity[i] = true; if(match[i] == -1 || Hungary(match[i])) { match[i] = u; return true; } } } return false; } void KM_perfect_match() { int temp; memset(lx, 0, sizeof(lx)); //初始化顶标 memset(ly, 0, sizeof(ly)); //ly[i]为0 for(int i = 0; i < n; ++i) //lx[i]为权值最大的边 for(int j = 0; j < n; ++j) lx[i] = max(lx[i], map[i][j]); for(int i = 0; i < n; ++i) //对n个点匹配 { 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) //x在交错树中 if(visitx[j]) for(int k = 0; k < n; ++k) //y在交错树外 if(!visity[k] && temp > lx[j] + ly[k] - map[j][k]) temp = lx[j] + ly[k] - map[j][k]; for(int j = 0; j < n; ++j) //更新顶标 { if(visitx[j]) lx[j] -= temp; if(visity[j]) ly[j] += temp; } } } } } int main() { int ans; while(scanf("%d", &n) != EOF) { ans = 0; memset(match, -1, sizeof(match)); for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) scanf("%d", &map[i][j]); KM_perfect_match(); for(int i = 0; i < n; ++i) //权值相加 ans += map[match[i]][i]; printf("%d\n", ans); } return 0; }
优化版本:
#include<iostream> #include<cstdio> #include<cstring> #include<climits> #include<algorithm> using namespace std; #define N 310 int map ; bool visitx , visity ; int lx , ly ; int slack ; int match ; int n; int Scan() { int res = 0 , ch ; while( !( ( ch = getchar() ) >= '0' && ch <= '9' ) ) { if( ch == EOF ) return 1 << 30 ; } res = ch - '0' ; while( ( ch = getchar() ) >= '0' && ch <= '9' ) res = res * 10 + ( ch - '0' ) ; return res ; } bool Hungary(int u) //匈牙利算法 { visitx[u] = true; for(int i = 0; i < n; ++i) { if(visity[i]) continue; 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)); //ly[i]为0 for(int i = 0; i < n; ++i) //lx[i]为权值最大的边 for(int j = 0; j < n; ++j) lx[i] = max(lx[i], map[i][j]); for(int i = 0; i < n; ++i) //对n个点匹配 { 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]) if(temp > slack[j]) 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 ans; while(scanf("%d", &n) != EOF) { ans = 0; memset(match, -1, sizeof(match)); for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) map[i][j] = Scan(); KM_perfect_match(); for(int i = 0; i < n; ++i) //权值相加 ans += map[match[i]][i]; printf("%d\n", ans); } return 0; }
相关文章推荐
- HDU 2255 奔小康赚大钱 km算法
- HDU 2255 奔小康赚大钱 KM裸题
- HDU 2255 奔小康赚大钱(KM算法模板题)
- HDU 2255 奔小康赚大钱(KM完美匹配)
- hdu_2255 奔小康赚大钱(KM算法)
- 【HDU 2255】【KM算法模板题+KM算法详解】 奔小康赚大钱
- HDU-2255 奔小康赚大钱 最大权值匹配
- hdu 2255 奔小康赚大钱(KM模板)
- hdu(2255)奔小康赚大钱
- hdu 2255 奔小康赚大钱 (km算法模板)
- hdu 2255 奔小康赚大钱 最大权匹配KM
- HDU 2255 奔小康赚大钱
- HDU2255——KM算法——奔小康赚大钱
- HDU 2255 奔小康赚大钱(KM模板)
- HDU - 2255 奔小康赚大钱 (KM图) (KM图模板)
- P - 奔小康赚大钱HDU 2255
- HDU 2255 奔小康赚大钱 (KM算法+二分图最大权匹配)
- hdu 2255奔小康赚大钱 KM算法模板
- HDU 2255 奔小康赚大钱 KM算法题解
- hdu 2255 奔小康赚大钱【Kuhn_Munkras】