POJ3249 工作难题(DAG有向无环图的单源最短路径)

题意:

有N个城市,它们之间存在一些单向路径,若可以从城市i到城市j,则一定无法从城市j到达城市i,只出不入的城市称为源点城市,只入不出的城市称为终点城市。已知到达某个城市就可以获得或者失去一定的钱财。现在狗先生从某个源点出发,到达某个终点停止,他想拥有尽量多的钱财。要求给出最多的钱财是多少。

分析:

题目给定的是一个有向无环图。最多的钱财可以转换成最短路径问题,每条边的权重其实就是到达该边的终点得到或失去的钱财。有向无环图的单源最短路径可以采用先拓扑排序再按照顺序遍历各个点的边进行松弛的方法进行。由于没有环,因此肯定存在最短路径。把最短路径转换为最长路径就可以解决这个问题了,同时这个题目给的是点权,将点权放在他的入度边上即可,没有入度的边再前面加一条即可,即设置一个超级源点,同时将出度是0的点连接到超级汇点,即可。

#include<cstdio>
#include<queue>
#include<cstring>

using namespace std;

const int maxn=1e5+10;
const int maxm=1e6+10;

#define inf 0x3f3f3f3f

struct node{
    int w,to,next;
}g[maxm<<1];

int head[maxn];
int cnt;
int iq;
int dis[maxn],in[maxn],out[maxn],val[maxn],que[maxn];

int n,m;

void add_edge(int u,int v,int w){
    ++in[v];
    ++out[u];
    g[cnt].to=v;
    g[cnt].w=w;
    g[cnt].next=head[u];
    head[u]=cnt++;
}

inline void init(){
    cnt=0;
    memset(head,-1,sizeof head);
    memset(in,0,sizeof in);
    memset(out,0,sizeof out);
}

void toposort(){
    iq=0;
    que[iq++]=0;
    for(int i=0;i<iq;i++){
        for(int k=head[que[i]];k+1;k=g[k].next){
            in[g[k].to]--;
            if(in[g[k].to]==0) que[iq++]=g[k].to;
        }
    }
}

void DAG(){
    for(int i=0;i<=n+1;i++){
        dis[i]=-inf;
    }
    dis[0]=0;
    for(int i=0;i<iq;i++){
        for(int k=head[que[i]];k+1;k=g[k].next){
            if(dis[g[k].to]<dis[que[i]]+g[k].w)
                dis[g[k].to]=dis[que[i]]+g[k].w;
        }
    }
}

int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        for(int i=1;i<=n;i++) scanf("%d",&val[i]);
        for(int i=0;i<m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,val[v]);
        }
        for(int i=1;i<=n;i++){
            if(in[i]==0) add_edge(0,i,val[i]);
            if(out[i]==0) add_edge(i,n+1,0);
        }
        toposort();
        DAG();
        printf("%d\n",dis[n+1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40679299/article/details/84104483
今日推荐