您的位置:首页 > 其它

poj 3160 Father Christmas flymouse (spfa + 强联通)

2013-01-12 22:13 302 查看
/*
 样例给的太水,对题目理解毫无作用。
 看了别人的报告才懂得。求最长路。有向图,可能有负边,也可能有环。
 所以先缩点,把环缩成一个点。
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
struct node
{
    int s,t,w;
};
vector<node>edge[3001];
vector<int>e[3001];
int dis[3001],in[3001],out[3001],a[3001],b[150001],c[150001];
int stack[3001],instack[3001],dfn[3001],low[3001],fa[3001],num[3001];//num是缩点后,每个点的权值。fa是每个点缩点后,属于那个新的点
int n,m,y,ind,cnt;
void init()//各种初始化
{
    memset(dfn,0,sizeof(dfn));
    memset(stack,0,sizeof(stack));
    memset(instack,0,sizeof(instack));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(num,0,sizeof(num));
    y=ind=cnt=0;
    int i;
    for(i=0;i<=3000;i++)
    {
        edge[i].clear();
        e[i].clear();
    }
}
void tarjan(int i)//强联通分量  模板
{
    int j,k;
    dfn[i]=low[i]=++ind;
    instack[i]=1;
    stack[y++]=i;
    for(j=0;j<e[i].size();j++)
    {
        k=e[i][j];
        if(!dfn[k])
        {
            tarjan(k);
            low[i]=min(low[i],low[k]);
        }
        else if(instack[k])
        low[i]=min(low[i],dfn[k]);
    }
    if(low[i]==dfn[i])
    {
        cnt++;
        int v;
        do
        {
            v=stack[--y];
            instack[v]=0;
            fa[v]=cnt;
            num[cnt]+=(a[v]>0?a[v]:0);//缩点时,每个点,只加正的点的值
        }while(v!=i);
    }
}
int spfa(int s)
{
    int i,j;
    for(i=1;i<=cnt;i++)
    {
        dis[i]=0;
    }
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int w=q.front();
        q.pop();
        for(j=0;j<edge[w].size();j++)
        {
            node p=edge[w][j];
            if(dis[p.t]<dis[w]+p.w)
            {
                q.push(p.t);
                dis[p.t]=dis[w]+p.w;
            }
        }
    }
    int ans=0;
    for(i=1;i<=cnt;i++)
    {
        if(out[i]==0)//终点的出度为0;
        ans=max(ans,dis[i]);
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        int i,j;
        for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&b[i],&c[i]);
            b[i]++;c[i]++;
            e[b[i]].push_back(c[i]);
        }
        for(i=1;i<=n;i++)
        {
            if(!dfn[i]) tarjan(i);
        }
        for(i=1;i<=m;i++)
        {
            int x=fa[b[i]];
            int y=fa[c[i]];
            if(x!=y)
            {
                in[y]++;out[x]++;
                node f;
                f.s=x;f.t=y;f.w=num[y];
                edge[x].push_back(f);
            }
        }
        for(i=1;i<=cnt;i++)//加一个虚拟的起点0,0到任意入度为0的i点的权值是num[i];
        {
            if(in[i]==0)
            {
                node g;
                g.s=0;
                g.t=i;
                g.w=num[i];
                edge[0].push_back(g);
            }
        }
        printf("%d\n",spfa(0));
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: