DP 挖地雷
原创
©著作权归作者所有:来自51CTO博客作者mb5f5b1df7f1e34的原创作品,请联系作者获取转载授权,否则将追究法律责任
题目描述】
在一个地图上有n个地窖(n≤200),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径,并规定路径都是单向的,且保证都是小序号地窖指向在序号地窖,也不存在可以从一个地窖出发经过若干地窖后又回到原来地窖的路径。某人可以从任一处开始挖地雷,然后沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使他能挖到最多的地雷。
【输入】
第一行:地窖的个数;
第二行为依次每个地窖地雷的个数;
下面若干行:
xi yixi yi //表示从xixi可到yiyi,xi<yixi<yi。
最后一行为"0 0"表示结束。
【输出】
k1−k2−…−kvk1−k2−…−kv //挖地雷的顺序
挖到最多的雷。
【输入样例】
6
5 10 20 5 4 5
1 2
1 4
2 4
3 4
4 5
4 6
5 6
0 0
【输出样例】
3-4-5-6
34
【来源】
No
题目分析:
经典的动态规划问题,题目规定,所有的路径都是单向的,所以满足DP无后效性原则和最优化原理。W[i]记录第id个地窖所持有的地雷数,a[i][j]记录第i个地窖与第j个地窖是否有通路,f【i】表示从i个地窖开始最多可以挖的地雷数
则状态转移方程:f[i]=max(f[j]+w[i]) (i<j<=n,a[i][j]=true)
边界条件:f[n]=w[n]
代码实现:
#include<bits/stdc++.h>
using namespace std;
int main()
{
long n,i,j,t,w[1000],maxx,f[1000],c[1000];
bool a[201][201];
cin>>n;
for(i=1;i<=n;i++)
cin>>w[i];
memset(a,false,sizeof(a));
memset(f,0,sizeof(f));
memset(c,0,sizeof(c));
f[n]=w[n]; //将最后一个地窖赋值给f[n],从后面f[n]往前找
do
{
cin>>i>>j;
a[i][j]=true;
}while(i!=0||j!=0);
a[0][0]=false;
for(i=n-1;i>=1;i--)
{ t=0;
maxx=0;
for(j=i+1;j<=n;j++)
if(a[i][j]==true&&f[j]>maxx)
{maxx=f[j];
t=j;}
c[i]=t;
f[i]=maxx+w[i];//保证从i地窖起能挖到后继点最大地雷数
}
int k=1;
for(j=2;j<=n;j++)
if(f[j]>f[k]) k=j;
maxx=f[k];
cout<<k;
k=c[k];
while(k!=0)
{
cout<<"-"<<k;
k=c[k];
}
cout<<endl;
cout<<maxx<<endl;
return 0;
}
但是我还有一个问题,请看我下面这个代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
long n,i,j,t,w[1000],maxx,f[1000],c[1000];
bool a[201][201];
cin>>n;
for(i=1;i<=n;i++)
cin>>w[i];
memset(a,false,sizeof(a));
memset(f,0,sizeof(f));
memset(c,0,sizeof(c));
f[n]=w[n]; //将最后一个地窖赋值给f[n]
do
{
cin>>i>>j;
a[i][j]=true;
}while(i!=0||j!=0);
a[0][0]=false;
for(i=n-1;i>=1;i--)
{ t=0;
for(j=i+1;j<=n;j++)
if(a[i][j]==true&&f[j]!=0&&f[j]+w[i]>f[i])//就这里不同
{f[i]=f[j]+w[i];
t=j;}
c[i]=t;
}
int k=1;
for(j=2;j<=n;j++)
if(f[j]>f[k]) k=j;
maxx=f[k];
cout<<k;
k=c[k];
while(k!=0)
{
cout<<"-"<<k;
k=c[k];
}
cout<<endl;
cout<<maxx<<endl;
return 0;
}
只能得到三十分,希望大神评论求解