比赛描述
FFF团,一个异端审判组织,团员活跃在各个角落,每当烧烤节来临的时候,我们都能听到他们传播的那熟悉的旋律:
烧啊~烧啊~烧啊烧啊烧~ (请自行脑补《当》)
FFF团成员自带这样一个属性:凭空变出火把与汽油,两者配合起来才能让FFF之火duang的一下烧起来,但是不同的火把与不同的汽油配合产生的火焰是不同的,现在有n种火把与n种汽油,已知每一种火把与每一种汽油配合时产生的火焰的旺盛程度,现在求怎样使得火把与汽油一一配对,产生最旺盛的火焰。
输入
第一行为一个整数T,表示有T组数据
每组数据第一行为一个正整数n(2≤n≤30)
第二行开始一共有n行,每行为n个正整数,第i行第j个数表示第i种火把与第j种汽油配合的火焰的旺盛程度。(0<a[i][j]≤10000)
输出
每组数据输出一个整数,表示最大的火焰旺盛程度
样例输入
2
3
5 2 6
6 7 9
7 4 1
4
8 5 2 8
5 8 2 1
9 6 3 7
7 5 8 1
样例输出
20
33
题目来源
kojimai
#include <iostream> #include<cstring> #include<cstdio> #include<cmath> //赤裸裸的模板啊。。 const int maxn = 101; const int INF = (1<<31)-1; int w[maxn][maxn]; int lx[maxn],ly[maxn]; //顶标 int linky[maxn]; int visx[maxn],visy[maxn]; int slack[maxn]; int nx,ny; bool find(int x){ visx[x] = true; for(int y = 0; y < ny; y++){ if(visy[y]){ continue; } int t = lx[x] + ly[y] - w[x][y]; if(t==0){ visy[y] = true; if(linky[y]==-1 || find(linky[y])){ linky[y] = x; return true; //找到增广轨 } }else if(slack[y] > t){ slack[y] = t; } } return false; //没有找到增广轨(说明顶点x没有对应的匹配,与完备匹配(相等子图的完备匹配)不符) } int KM() //返回最优匹配的值 { int i,j; memset(linky,-1,sizeof(linky)); memset(ly,0,sizeof(ly)); for(i = 0; i < nx; i++){ for(j = 0,lx[i] = -INF; j < ny; j++){ if(w[i][j] > lx[i]){ lx[i] = w[i][j]; } } } for(int x = 0; x < nx; x++){ for(i = 0; i < ny; i++){ slack[i] = INF; } while(true){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(find(x)){ //找到增广轨,退出 break; } int d = INF; for(i = 0; i < ny; i++){ //没找到,对l做调整(这会增加相等子图的边),重新找 if(!visy[i] && d > slack[i]){ d = slack[i]; } } for(i = 0; i < nx; i++){ if(visx[i]){ lx[i] -= d; } } for(i = 0; i < ny; i++){ if(visy[i]){ ly[i] += d; }else{ slack[i] -= d; } } } } int result = 0; for(i = 0; i < ny; i++){ if(linky[i]>-1){ result += w[linky[i]][i]; } } return result; } int main(){ // freopen("test.txt","r",stdin); int t,i,j,k; scanf("%d",&t); while(t--){ // scanf("%d%d",&nx,&ny); scanf("%d",&nx); ny = nx; for(i=0; i<nx; i++){ for(j=0; j<ny; j++){ scanf("%d",&k); w[i][j] = k; } } printf("%d\n",KM()); } } /* AC #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> using namespace std; #define FFF 35 #define MAX 0x3f3f3f3f int len[FFF][FFF]; // int sx[FFF],sy[FFF]; int lx[FFF],ly[FFF]; int match[FFF],n; int bfs(int i) { sx[i] = 1; for(int j = 1;j <= n;j++) { if(!sy[j] && lx[i] + ly[j] == len[i][j]) { sy[j] = 1; if(!match[j] || bfs(match[j])) { match[j] = i; return 1; } } } return 0; } int km(int n) { for(int i = 1;i <= n;i++) { lx[i] = len[i][1]; for(int j = 2;j <= n;j++) lx[i] = max(lx[i],len[i][j]); } memset(ly,0,sizeof(ly)); memset(match,0,sizeof(match)); for(int x = 1;x <= n;x++) { while(1) { memset(sx,0,sizeof(sx)); memset(sy,0,sizeof(sy)); if(bfs(x)) break; int d = MAX; for(int i = 1;i <= n;i++) { if(sx[i]) for(int j = 1;j <= n;j++) if(!sy[j]) d = min(d,lx[i] + ly[j] - len[i][j]); } for(int i = 1;i <= n;i++) if(sx[i]) lx[i] -= d; for(int j =1;j <= n;j++) if(sy[j]) ly[j] += d; } } int sum = 0; for(int i = 1;i <= n;i++) sum += lx[i]; for(int i = 1;i <= n;i++) sum += ly[i]; return sum; } int main() { int t; // freopen("out.out","w",stdout); cin >> t; while(t--) { cin >> n; for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) scanf("%d",&len[i][j]); cout<<km(n)<<endl; } return 0; } */ /*Time Limit Exceed at Test 1 这个算法的复杂度为 指数级函数 #include<iostream> #define MAX_N 30 int a[MAX_N][MAX_N],n,maxFire,fire; bool visited[MAX_N]; void dfs(int i){ if(i==n){ return; } for(int j=0; j<n; j++){ if(!visited[j]){ visited[j] = 1; fire += a[i][j]; if(fire>maxFire){ maxFire = fire; } dfs(i+1); fire -= a[i][j]; visited[j] = 0; } } } int main(){ int t,i,j; scanf("%d",&t); while(t--){ scanf("%d",&n); memset(visited,0,n); for(i=0;i<n;i++){ for(j=0;j<n;j++){ scanf("%d",&a[i][j]); } } dfs(0); printf("%d\n",maxFire); } } */