洛谷p2196挖地雷

dp
一开始按照书上的方法用dp写

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
    long f[201]={0},w[201],c[201]={0};
    bool a[201][201]={0};
    long i,j,n,x,y,l,k,maxx;
    memset(f,0,sizeof(f));
    memset(c,0,sizeof(c));
    memset(a,false,sizeof(a));
    cin>>n;
    for(i=1;i<=n;i++)
        cin>>w[i];                               
    do
    {
      cin>>x>>y;                              
      if((x!=0)&&(y!=0)) a[x][y]=true;
    }while((x!=0)||(y!=0));
    f[n]=w[n];                                 
    for(i=n-1;i>=1;i--)
    {
        l=0;k=0;
        for(j=i+1;j<=n;j++)
        if((a[i][j])&&(f[j]>l))
        { 
            l=f[j];
            k=j; 
        }
        f[i]=l+w[i];                            
        c[i]=k;                                  
    }
    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;                          
}

三个tle一个wa
然后放弃dp了……(当然可以用dp……)
接下来才是重点
核心部分–链表遍历(其实只是比较像)
存三个参数a[i][1]来存储当前地窖有多少个地雷,a[i][2]来存储通过这个地窖最多可以挖到多少个地雷,a[i][3]来存储,如果要挖到最多的地雷,我们经过这个地窖之后要去哪个地窖。
跟p1020的最长不下降子序列有点像啊……
具体看代码吧(附带注释)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    bool f[210][210];//邻接矩阵
    int a[210][4],n;//a数组
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i][1]);//读入地雷数量
        a[i][2]=a[i][1];//默认最长和是自身
        a[i][3]=0;//后继是0代表结束
    }
    for(int i=0;i<=209;i++)
    for(int j=0;j<=209;j++)
    f[i][j]=false;//邻接矩阵的初始化,默认都不能通
    int x=0;
    for(int i=1;i<=n-1;i++)
    for(int j=i+1;j<=n;j++)
    {
        cin>>x;
        if(x==1) f[i][j]=true;//在图中造路
    }

    for(int i=n-1;i>=1;i--)
    {
        int maxx=0,next=0;//maxx代表当前这个地窖过去以后可以挖掉多少地雷,next代表要挖到最多的地雷,接下来应该去哪里
        for(int j=i+1;j<=n;j++)
        if((a[j][2]>maxx)&&(f[i][j]))//如果能挖到的地雷多于当前记录的,并且ij之间通路
        {
            maxx=a[j][2];
            next=j;//更新累加和与标记
        }
        if(next>0)//如果更改过
        {
            a[i][2]=a[next][2]+a[i][1];//那么就把累加和记录进去
            a[i][3]=next;//更新当前结点的后继
        }
    }
    int ans=0;
    int first=0;
    for(int i=1;i<=n;i++)
    if(a[i][2]>ans)
    {
        ans=a[i][2];
        first=i;
    }//来寻找要挖到最多的地雷,第一个对哪个地窖下手。
    while(first>0)//真的像链表遍历
    {
        printf("%d ",first);//打印路径
        first=a[first][3];
    }
    printf("\n%d",ans);//把路径长度打印出来
    return 0;
}

庆祝ac
(ppt就不弄了)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值