ZOJ1609-Equivalence

探讨了在给定命题间证明难度的情况下,如何通过状态压缩和搜索算法找到使所有命题形成等价关系所需的最小总难度。问题抽象为寻找使有向图强连通的最小边权总和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Equivalence

Time Limit: 5 Seconds      Memory Limit: 32768 KB

When learning mathamatics, sometimes one may come to an theorem which goes like this:

The following statements are equivalent:

a)......
b)......
c)......

For example, let A be an angle between 0 and 360 degrees, the following statements are equivalent:

a)A = 90 degrees;
b)A is a right angle;
c)sin(A) = 1.

Proving such a theorem is usually a difficult task, because you have to prove that for any two statements Si and Sj, Si concludes Sj and vise versa. Sometimes, proving Si concludes Sj directly is quite difficult so we may find a Sk and prove that Si concludes Sk and Sk concludes Sj. Now given the difficulty of proving every Si => Sj, you are to calculate the minimal total difficulty to prove that the given statements are equivalent.


Input

The input contains several cases. Each case begins with an integer n (2 <= n <= 6), the number of statements in this case, followed by n lines, each contains n integers.

The jth integer of the ith row represents the difficulty of proving Si => Sj. The ith integer of the ith row is always 0 as it's obvious that Si concludes Si. All the n * n integers are between 0 and 100, inclusively. Input is terminated by EOF.


Output

For each test case, output a line with the minimal difficulty for that case.


Sample Input

4
0 2 3 4
5 0 7 8
9 10 0 12
13 14 15 0


Sample Output

34



Author: PAN, Minghao
Source: ZOJ Monthly, May 2003


题意:有n个点,告诉你两两之间有向边的权值,问使整张图强连通的最小权值为多少

解题思路:暴搜+剪纸+状态压缩


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;
const double pi = acos(-1.0);

struct node
{
	int x, y, sum;
} xx[50];
int n, cnt, mi,m;
int a[10][10], b[50][8];

bool cmp(node xx, node yy)
{
	return xx.sum < yy.sum;
}

void dfs(int x,int sum)
{
	if (sum >= mi) return;
	int res = 0;
	for (int i =0 ; i < n; i++)
	{
		res += b[x][i] == m;
		b[x + 1][i] = b[x][i];
	}
	if (res==n)
	{
		mi = min(mi, sum);
		return;
	}
	if(x==cnt) return ;
	for (int i = 0; i < n; i++)
	{
		b[x + 1][i] = b[x][i];
		if (b[x][i] & (1 << xx[x].x))
		{
			b[x + 1][i] |= b[x][xx[x].y];
		}
	}
	dfs(x + 1, sum + xx[x].sum);
	for (int i = 0; i < n; i++) b[x + 1][i] = b[x][i];
	dfs(x + 1, sum);
}

int main()
{
	while (~scanf("%d", &n))
	{
		cnt = 0;
		m = (1 << n) - 1;
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				scanf("%d", &a[i][j]);
				if (i == j) continue;
				xx[cnt].x = i, xx[cnt].y = j, xx[cnt++].sum = a[i][j];
			}
		}
		sort(xx,xx+cnt,cmp);
		for (int i = 0; i < n; i++)  b[0][i] = 1 << i;
		mi = INF;
		dfs(0, 0);
		printf("%d\n", mi);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值