挖地雷
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; }