zoukankan      html  css  js  c++  java
  • [USACO15JAN]草鉴定Grass Cownoisseur

    tarjan缩点+最短路

    这道题我想了一半的正解,就是缩点+DAG上考虑,之后图只有一种情况:1号点连着大量的点,大量的点连着1号点,部分能到达1号点的点连接着1号点能到达的部分点。转向就是要从1号点能到达的点过渡到能到达1号点的点。考虑spfa,在缩完点后的图上从1号点正向跑最大路,再建立一个反图,跑最大路。这样我们枚举每一个点(缩后的点),找到他连接的点,如果合法,那么ans=max(ans,-1*val[firs]+diss[i]+disf[v]);

    code:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #include<vector>
    #include<stack>
    using namespace std;
    const int maxn=500006;
    int x1,x2,y1,y2;
    struct hzw
    {
      int to,next,u;
    }e[maxn],ed1[maxn],ed2[maxn];
    int head[maxn],head1[maxn],head2[maxn],cur,n,m,k;
    inline void add(int a,int b,hzw e[],int head[])
    {
      e[cur].u=a;
      e[cur].to=b;
      e[cur].next=head[a];
      head[a]=cur++;
    }
    stack<int>ss;
    bool pan[maxn];
    int cnt,col,val[maxn],firs,low[maxn],dfn[maxn],bel[maxn],disf[maxn],diss[maxn];
    inline void tarjan(int s)
    {
        low[s]=++cnt;
        dfn[s]=cnt;
        ss.push(s);
        for (int i=head[s];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            if (!dfn[v])
            {
                tarjan(e[i].to);
                low[s]=min(low[s],low[v]);
            }
            else if (!pan[v])
            {
                low[s]=min(low[s],dfn[v]);
            }
        }
        if (low[s]==dfn[s])
        {	
        	col++;
            while (ss.top()!=s)
            {
                int fr=ss.top();
                ss.pop();
                pan[fr]=1;
                bel[fr]=col;
                val[col]++;
                if (fr==1) firs=col;
            }
            int fr=ss.top();
            ss.pop();
            pan[fr]=1;
            bel[fr]=col;
            val[col]++;
           	if (fr==1) firs=col;
        }
    }
    bool vis[maxn];
    void spfa(int s,hzw e[],int dis[],int *head){
        memset (vis,0,sizeof (vis));
        memset(dis,-1,sizeof(dis));
        queue<int>q;
        q.push(s);
        dis[s]=val[firs];
        vis[s]=true;
        while (!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=false;
            for (int i=head[u];i!=-1;i=e[i].next){
                int a=e[i].to;
                if (dis[a]<dis[u]+val[a]){
                    dis[a]=dis[u]+val[a];
                    if (!(vis[a])){
                        q.push(a);
                        vis[a]=true;
                    }
                }
            }
        }
    }
    int main()
    {
        
        memset(head,-1,sizeof(head));
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        cin>>n>>m;
        for (int i=1,a,b;i<=m;++i)
        {
            scanf("%d%d",&a,&b);
            add(a,b,e,head); 
        }
        for (int i=1;i<=n;++i) if (!dfn[i]) {tarjan(i);}
        for (int i=0;i<m;++i)
        {
            int x=bel[e[i].u],y=bel[e[i].to];
            if (x!=y)
            {
                add(x,y,ed1,head1);
                add(y,x,ed2,head2);
            }
        }
        spfa(firs,ed1,disf,head1);
        spfa(firs,ed2,diss,head2);
        int ans=val[firs];
        for (int i=1;i<=col;++i)
        {
        	if (!diss[i]) continue;
        	for (int j=head1[i];j!=-1;j=ed1[j].next)
        	{
        		int v=ed1[j].to;
        		if (!disf[v]) continue;
        		ans=max(ans,-1*val[firs]+diss[i]+disf[v]);
            }
        }
        cout<<ans;
        return 0;
    }
    

    收获:

    注意最长,最短路有时能解决常见的dp问题(有起点的那种),并且能够判断状态是否合法。

  • 相关阅读:
    Linux内核使用的GNUC扩展
    linux常用命令--开发调试篇
    代码示例_poll的多路复用
    硬件_红外传感器
    硬件_霍尔感应器
    全志_功能引脚配置_sys_config.fex
    知识_嵌入式常用词汇
    代码示例_Input 按键驱动
    Vmware_安装_tools
    Ubunt_配置_start
  • 原文地址:https://www.cnblogs.com/bullshit/p/9688544.html
Copyright © 2011-2022 走看看