POJ 3249 Test for Job 解题报告 DP

题目意思:
给出一个有向图,但是这个图不一定联通而且保证无环。每个点上都有一个权值。问题是:从任意一个入度为0的点出发,目标是到达任意一个岀度为0的点,问所有的方法中,路上经过点的权值和最大为多少?
输入:
包含多组数据;
先输入两个数n,m;代表有n个点,m条边;
接下来n行,每行一个数,代表每个点的权值是多少;
接下来m行,每行两个数x,y,代表从x到y有一条路;
输出:路上经过的点权值和最大值

PS:有一点非常坑,点的权值可能是负数!(在这里感谢现在坐在我旁边的逗比 猪888 同学,是他提醒我有负数让我在WA了两次之后一遍AC);还有,记得是多组数据,记得数组清零;最后一点,数据范围,n是坑爹的100000,m是1000000;

现在大概讲一下思路是什么—->

先思考一下对于某一个中间点:
这个点要是需要走到某个岀度为0的点去,那么显然,他是需要走到他的一个儿子那里去的(貌似这是废话);
要是他的儿子已经计算出来最优解的话,那么就显然了;
这个点的走向显然是向最优解值最大的那个儿子~

那么,假设当前点为x,x最优解最大的那个儿子为y;
显然 dp[x]=max(dp[x],dp[y]+a[x]);
//a[x]是x点的权值

现在来考虑边界条件::::
其实不需要什么太多考虑
边界条件就是每个岀度为0的点啦
dp[x]=a[x]//x是某个出度为0的点

OK,现在放代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=100010,maxm=1000010;
const int zhf=2147483647;
int e,to[maxm],be[maxn],nxt[maxm],rd[maxn],cd[maxn],n,m;//这是链式前向星的一堆东西,还有入度(rd)岀度(cd)这些杂七杂八的
int dp[maxn];//这个数组是存放每个点的走到终点去最优解的
int a[maxn];//这个显然是每个点的权值
bool p[maxn];//用于记忆化搜索
void clear(){//每次记得清空
    e=0;
    memset(to,0,sizeof(to));
    memset(be,0,sizeof(be));
    memset(nxt,0,sizeof(nxt));
    memset(a,0,sizeof(a));
    memset(rd,0,sizeof(rd));
    memset(cd,0,sizeof(cd));
    memset(dp,0,sizeof(dp)); 
    memset(p,0,sizeof(p));
}
void add(int x,int y){ //链式前向星的东西,没什么好讲的
    to[++e]=y;
    nxt[e]=be[x];
    be[x]=e;
}
int query(int x){//这个函数返回从点出发x的最优解是多少
    if(p[x])return dp[x];//记忆化搜索
    int ans=dp[x];//ans是迭代的东西
    for(int i=be[x];i;i=nxt[i]){//调用链式前向星
        int y=to[i];//显然,y是x的儿子之一
        ans=max(ans,query(y)+a[x]);//状态转移方程
    }
    p[x]=1;//表示已经计算过了
    return dp[x]=ans;
}
int main(){
    int i,j,k;
    while(scanf("%d%d",&n,&m)!=EOF){//显然
        clear();//记得清零
        for(i=1;i<=n;i++){
            scanf("%d",a+i);
            dp[i]=-zhf;//记得有负数,这个坑死我了
        }
        for(i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            cd[u]++;
            rd[v]++; //显然
        }
        //for(j=1;j<=n;j++)for(i=be[j];i;i=nxt[i])printf("Start:%d -> To:%d\n",j,to[i]);return 0;
        //显然这个注释可以让你看看链式前向星在干什么
        int ans=-zhf;
        for(i=1;i<=n;i++)
            if(cd[i]==0){
                dp[i]=a[i];
                p[i]=1;
            }
        for(i=1;i<=n;i++){
            if(rd[i]==0)
            //  printf("query(%d):%d\n",i,query(i));
            //可以看看每一个点的答案啊~~~不过要注释掉那个if
                ans=max(query(i),ans);
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值