南邮 OJ 2073 FFF

FFF

时间限制(普通/Java) :  1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 162            测试通过 : 18 

比赛描述

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

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);
	}
}
*/


你可能感兴趣的:(ACM,fff,南邮OJ)