码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3249 拓扑+dp

时间:2015-03-27 23:36:03      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:

Test for Job
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 9479   Accepted: 2168

Description

Mr.Dog was fired by his company. In order to support his family, he must find a new job as soon as possible. Nowadays, It‘s hard to have a job, since there are swelling numbers of the unemployed. So some companies often use hard tests for their recruitment.

The test is like this: starting from a source-city, you may pass through some directed roads to reach another city. Each time you reach a city, you can earn some profit or pay some fee, Let this process continue until you reach a target-city. The boss will compute the expense you spent for your trip and the profit you have just obtained. Finally, he will decide whether you can be hired.

In order to get the job, Mr.Dog managed to obtain the knowledge of the net profit Vi of all cities he may reach (a negative Vi indicates that money is spent rather than gained) and the connection between cities. A city with no roads leading to it is a source-city and a city with no roads leading to other cities is a target-city. The mission of Mr.Dog is to start from a source-city and choose a route leading to a target-city through which he can get the maximum profit.

Input

The input file includes several test cases. 
The first line of each test case contains 2 integers n and m(1 ≤ n ≤ 100000, 0 ≤ m ≤ 1000000) indicating the number of cities and roads. 
The next n lines each contain a single integer. The ith line describes the net profit of the city iVi (0 ≤ |Vi| ≤ 20000) 
The next m lines each contain two integers xy indicating that there is a road leads from city x to city y. It is guaranteed that each road appears exactly once, and there is no way to return to a previous city. 

Output

The output file contains one line for each test cases, in which contains an integer indicating the maximum profit Dog is able to obtain (or the minimum expenditure to spend)

Sample Input

6 5
1
2
2
3
3
4
1 2
1 3
2 4
3 4
5 6

Sample Output

7

Hint

技术分享
 
题目意思:
给一个n个结点、m条边的图,图无环无重边,每个结点上有一个价值可能为正也可能为负,求从起点到终点最多的价值。起点为没有入度的点,终点为没有出度的点。
 
思路:
很明显dp,起点dp[u]=pri[u],然后以后的点都是dp[v]=max(dp[v],dp[u]+pri[v]);
刚开始用bfs超时了,bfs是从每个起点开始bfs,然后求终点最大的即可。
超时是必然的。。。如下图:
技术分享
技术分享
 
且不管结点5以后的价值,若用bfs的话,先从1bfs遍历到8,然后从2bfs遍历到8.。。。从4遍历到8。
发现了没,咱们只需要遍历到5就行了,后面的都是一样的,加上最大的5即可,所以bfs遍历的有点多余了,那么超时是必然的。
 
那么拓扑排序呢?拓扑排序时,只有5的入度为0时才把5放在队列里面,后面的结点仅且入队一次,那么就没有多余入队了,轻轻松松就A了。
 
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
using namespace std;

#define N 100005
#define inf 999999999

int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int abs(int x,int y){return x<0?-x:x;}

int dis[N], dp[N];
int n, m;
bool visited[N];
int in[N];
int out[N];

struct Edge{
    int u, v, next;
}e[1000005];
int head[1000005];
int cnt;

void setEdge(int u,int v){
    e[cnt].u=u;e[cnt].v=v;e[cnt].next=head[u];
    head[u]=cnt++;
}

/*void bfs(int u){          //bfs超时代码
    queue<int>Q;
    while(!Q.empty()) Q.pop();
    Q.push(u);visited[u]=true;dp[u]=dis[u];
    int i, v;
    while(!Q.empty()){
        u=Q.front();Q.pop();visited[u]=false;
        for(i=head[u];i!=-1;i=e[i].next){
            if(!visited[e[i].v]&&dp[e[i].v]<dp[u]+dis[e[i].v]){
                dp[e[i].v]=dp[u]+dis[e[i].v];Q.push(e[i].v);visited[e[i].v]=true;
            }
        }
    }
}*/

void tp(){
    queue<int>Q;
    int i, j, k;
    for(i=1;i<=n;i++){
        if(!in[i])
            Q.push(i),dp[i]=dis[i];
    }
    int u;
    while(!Q.empty()){
        u=Q.front();Q.pop();
        for(i=head[u];i!=-1;i=e[i].next){
            dp[e[i].v]=max(dp[e[i].v],dp[u]+dis[e[i].v]);
            in[e[i].v]--;
            if(!in[e[i].v]) Q.push(e[i].v);
        }
    }
}

main()
{
    int i, j, k;
    while(scanf("%d %d",&n,&m)==2){
        for(i=1;i<=n;i++) scanf("%d",&dis[i]);
        for(i=0;i<=n;i++) dp[i]=-inf;
        cnt=0;
        memset(head,-1,sizeof(head));
    //    cout<<endl;
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        int x, y;
        while(m--){
            scanf("%d %d",&x,&y);
            setEdge(x,y);
            in[y]++;
            out[x]++;
        }
        memset(visited,false,sizeof(visited));
        tp();
        int ans=-inf;
        for(i=1;i<=n;i++){
        //    printf("%d ",dp[i]);
            if(!out[i]&&ans<dp[i]) 
                ans=dp[i];
        }
    //    cout<<endl;
        printf("%d\n",ans);
    }
    return 0;
}

 

 
技术分享

POJ 3249 拓扑+dp

标签:

原文地址:http://www.cnblogs.com/qq1012662902/p/4373093.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!