【9902】挖地雷

挖地雷

Time Limit: 10 second
Memory Limit: 2 MB

问题描述
在一个地图上有n个地窖(n≤200),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径,并规定路径都是单向的。某人可以从任一处开始挖地雷,然后沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使他能挖到最多的地雷。(只由小序号的地窖指向大序号地窖。且不会出现环。

Input

n //地窖的个数
w1 w2 w3 w4 ... wn //每个地窖中的地雷数
x1 y1 //表示从x1可到y1
x2 y2
...
0 0 //表示输入结束

Output

k1-k2-...kv //挖地雷的顺序
max //最多挖出的地雷数

Sample Input

6
5 10 20 5 4 5
1 2
1 4
2 4
3 4
4 5
4 6
5 6
0 0

Sample Output

3-4-5-6
34

【题解】

因为序号只会由小序号指向大序号。所以存在单调性。逆推。

f[n-1]推完后,1..n-2都不会再影响到n-1的结果了。所以不用再考虑n-1.即无后效性。

一开始1..n f[i] = w[i];

for (int i = n;i >=1 ;i--)

for (int j = 1;j <= i-1;j++)

if (a[j][i] && f[j] < f[i]+w[j])

f[j] = f[i]+w[j];

【代码】

#include <cstdio>
#include <cstring>

int n,w[201],f[201],next[201];
bool a[201][201];

int main()
{
	memset(a,false,sizeof(a));
	scanf("%d",&n);
	for (int i = 1; i<= n;i++)
		scanf("%d",&w[i]);
	int x,y;
	scanf("%d%d",&x,&y); //因为不会出现0节点 所以出现0就直接结束输入 
	while (x!=0)
		{
			a[x][y] = true;	
			scanf("%d%d",&x,&y);
		}
	for (int i = 1;i <= n;i++) //一开始f的初值即为地窖里的地雷数目。 
		f[i] = w[i],next[i] = 0;
	for (int i = n;i>=1;i--)
		for (int j = 1;j<= i-1;j++) //从前面的节点。到后面的节点,尝试用后面的节点的最优值更新前面节点的最优值 
			if (a[j][i] && f[j] < f[i]+w[j])
				f[j] = f[i]+w[j],next[j] = i; //记录下j的后继节点 
	int k =1,ma = f[1];
	for (int i = 2;i <= n;i++) //找到最优值最大的节点在什么地方。记录下来 
		if (f[i] > ma)
			ma = f[i],k = i;
	printf("%d",k); //输出路径 
	while (next[k]!=0)
		{
			k = next[k];
			printf("-%d",k);
		}
	printf("
%d",ma);
	return 0;	
}



原文地址:https://www.cnblogs.com/AWCXV/p/7632344.html