POJ 3249 Test for Job

题目连接为:http://poj.org/problem?id=3249

大意如下:

给定n个城市,m个路径,每个城市有对应的收入(可能为负值)。起始城市(source-city)为入度为0的城市,目标城市(target-city)为出度为零的城市。

求出在给定的情况下,从起始城市到目标城市的最大收入。

思路:题目给出的图是DAG,所以对其进行拓扑排序,再利用动态规划方程: dp[v]=max(dp[v],dp[u]+w[v]);

拓扑排序得到的是对图中的点的顺序。

拓扑排序的方法有两种: 

一。记录所有点的入度和出度

       (1)从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它.(利用队列,将所有入度为0的点加入到队列中)
       (2)从网中删去该顶点,并且删去从该顶点发出的全部有向边.(邻接表中的每个点的入度减一,将删除的节点按照顺序放到数组中,或对点进行标号,这样形成的就是拓扑序)
       (3)重复上述两步,直到剩余的网中不再存在没有前趋的顶点为止.(当队列为空时,完成对所有点的搜索)
       本题的代码就是利用该方法得到拓扑序的。

二。利用DFS

      反复利用DFS过程,直到所有点用完。 在DFS过程中,将完成搜索的点放到链表的头部(相当于栈的压栈操作)。

     最后形成的链表就是有向图的拓扑序。


#include <algorithm>
#include <bitset>
#include <deque>
#include <functional>
#include <fstream>
#include <list>
#include <iostream>
#include <iomanip>
#include <iterator>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <string>
#include <stack>
#include <sstream>
#include <utility>
#include <vector>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <climits>

#define up(i, lower, upper) for(int i = lower; i < upper; i++)
#define down(i, lower, upper) for(int i = upper-1; i >= lower; i--)

using namespace std;

#define MAX_N 100010
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef long long ll;
typedef unsigned long long ull;

const double pi = acos(-1.0);
const double eps = 1.0e-9;

template<class T>

inline bool read(T &n){
	T x = 0, tmp = 1; char c = getchar();
	while ((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
	if (c == EOF) return false;
	if (c == '-') c = getchar(), tmp = -1;
	while (c >= '0' && c <= '9') x *= 10, x += (c - '0'), c = getchar();
	n = x*tmp;
	return true;
}

template <class T>
inline void write(T n) {
	if (n < 0) {
		putchar('-');
		n = -n;
	}
	int len = 0, data[20];
	while (n) {
		data[len++] = n % 10;
		n /= 10;
	}
	if (!len) data[len++] = 0;
	while (len--) putchar(data[len] + 48);
}


const int MAXN = 100001;

int a[MAXN], ind[MAXN], outd[MAXN], dp[MAXN];
vector<int> e[MAXN];
queue<int> q;

int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF)
    {
        for (int i = 1; i <= n; ++ i)
        {
            scanf("%d", &a[i]);
            e[i].clear();
            dp[i] = INT_MIN;
            ind[i] = outd[i] = 0;
        }
        while (m --)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            e[x].push_back(y);
            ++ ind[y];
            ++ outd[x];
        }
        for (int i = 1; i <= n; ++ i)
            if (!ind[i])
            {
                dp[i] = a[i];
                q.push(i);
            }
        while (!q.empty())
        {
            int cur = q.front();
            q.pop();
            for (int i = 0; i < e[cur].size(); ++ i)
            {
               dp[e[cur][i]] =  max(dp[e[cur][i]], dp[cur] + a[e[cur][i]]);
                if (-- ind[e[cur][i]] == 0)
                    q.push(e[cur][i]);
            }
        }
        int ans = INT_MIN;
        for (int i = 1; i <= n; ++ i)
            if (!outd[i])
               ans = max(ans, dp[i]);
        printf("%d\n", ans);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值