luogu2196 【1996提高】挖地雷(记忆化搜索/dp)

来源:互联网 发布:拒绝退款后淘宝介入 编辑:程序博客网 时间:2024/06/04 23:31

这道题以前写的时候想不明白为什么能dp,所以固执的写了记忆化搜索。。。现在一想其实很简单,这道题给的图其实是很特殊的,每个点只可能与在它后面的点有有向边。所以可以倒着dp,满足了无后效性和最优子结构。

dfs+记忆化

#include<cstdio>#include<cstring>int const N=25;int n,w[N],a[N][N],road[N],bestroad[N],ans=0,anss=0;bool f[N],ff[N];inline int read(){    int x=0;char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x;}void dfs(int id,int tot,int cnt){//第几个地窖,总共挖了过少,在挖第几个     road[cnt]=id;    ff[id]=1;    for(int i=1;i<=n;i++){        if(a[id][i]&&!f[i]){            f[i]=1;dfs(i,tot+w[id],cnt+1);            f[i]=0;        }    }    if(tot+w[id]>ans){        ans=tot+w[id];        for(int i=1;i<=cnt;i++) bestroad[i]=road[i];        anss=cnt;    }}inline int max(int x,int y){return x>y?x:y;}int main(){//  freopen("P2196.in","r",stdin);//  freopen("P2196.out","w",stdout);    n=read();    for(int i=1;i<=n;i++) w[i]=read();    for(int i=1;i<=n;i++)    for(int j=i+1;j<=n;j++) a[i][j]=read();    for(int i=1;i<=n;i++) if(!ff[i]) dfs(i,0,1);    for(int i=1;i<anss;i++) printf("%d ",bestroad[i]);    printf("%d\n%d",bestroad[anss],ans);    return 0;}

dp

#include <cstdio>#include <cstring>#define N 25bool map[N][N];int n,w[N],f[N],to[N],ans=0;int main(){//  freopen("a.in","r",stdin);    scanf("%d",&n);    for(int i=1;i<=n;++i) scanf("%d",&w[i]),f[i]=w[i];    for(int i=1;i<=n-1;++i)        for(int j=i+1;j<=n;++j)            scanf("%d",&map[i][j]);    for(int i=n-1;i>=1;--i)        for(int j=i+1;j<=n;++j)            if(map[i][j]&&w[i]+f[j]>f[i]) f[i]=w[i]+f[j],to[i]=j;    for(int i=1;i<=n;++i) if(f[i]>f[ans]) ans=i;    int k=ans;    while(to[k]) printf("%d ",k),k=to[k];    printf("%d\n%d",k,f[ans]);    return 0;}
原创粉丝点击