poj 3249 Test for Job

【题意】

n个点m条有向边,每个点有一个权值v[i],求一条从入度为0的点到出度为0的点路径上的经过所有点权值之和最小值。保证:

t is guaranteed that each road appears exactly once, and there is no way to return to a previous city. (实际上是告诉无环)

1 ≤ n ≤ 100000, 0 ≤ m ≤ 1000000

【题解】

第一开始拆点用spfa做结果一直T,后来就用记忆化搜索(dp)写了就A了。

拓扑排序+DP我写的会T……发现记忆化搜索是个好东西,既快又好写。看来我以后还是少写拓扑排序吧,反正都可转化为记忆化搜索。

【Code】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=210000;
const int inf=1<<30;
int v[maxn],dout[maxn];
int f[maxn];
vector<int>pre[maxn];
void dp(int x)
{
    if(f[x]>-inf)return;
    if(pre[x].size()==0)
    {
        f[x]=v[x];
        return;
    }

    int tn=pre[x].size();
    for(int i=0;i<tn;i++)
    {
        int y=pre[x][i];
        dp(y);
        if(f[y]+v[x]>f[x])f[x]=f[y]+v[x];
    }
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {

        for(int i=0;i<=n+1;i++)
        {
            pre[i].clear();
            dout[i]=0;
            v[i]=0;
        }

        for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);

        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            dout[x]++;
            pre[y].push_back(x);
        }

        for(int i=0;i<=n+1;i++)
        f[i]=-inf;

        for(int i=1;i<=n;i++)
        if(dout[i]==0)
        {
            pre[n+1].push_back(i);
        }

        dp(n+1);
        printf("%d\n",f[n+1]);
    }
    return 0;
}


你可能感兴趣的:(poj 3249 Test for Job)