首页 > 代码库 > hdu 3639 有向图缩点+建反向图+搜索

hdu 3639 有向图缩点+建反向图+搜索

题意:给个有向图,每个人可以投票(可以投很多人,一次一票),但是一个人只能支持一人一次,支持可以传递,自己支持自己不算,被投支持最多的人。

开始想到缩点,然后搜索,问题是有一点想错了!以为支持按票数计算,而不是按人数!还各种树形dp/搜索求可以到达边数。。提交WA了。。。

又反复读了题目之后才发现。。错误。。只要人数就行。。。问题简单了许多。。。

缩点成有向无环图后:每个SCC中支持的人数就是scc里面的人,要求可到达的点最多的点,当然要放过来求方便:反向图那个点可以到达的点最多!于是建反向图直接dfs即可,记录答案有点麻烦。。。提交就A了。。。这题总体花了我2多个小时。。算失败。。。

#include<iostream>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxv=5005,maxe=50005;
int nume=0;int head[maxv];int e[maxe][3];
void inline adde(int i,int j,int c)
{
    e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
    e[nume++][2]=c;
}
int dfn[maxv];int low[maxv];int vis[maxv];int ins[maxv]; stack<int>sta;
int scc[maxv];int numb=0;int times=0;
int n,m;  int sccsize[maxv];
void tarjan(int u)
{
    dfn[u]=low[u]=times++;
    ins[u]=1;
    sta.push(u);
    for(int i=head[u];i!=-1;i=e[i][1])
    {
        int v=e[i][0];
        if(!vis[v])
        {
            vis[v]=1;
            tarjan(v);
            if(low[v]<low[u])low[u]=low[v];
        }
        else if(ins[v]&&dfn[v]<low[u])
        {
            low[u]=dfn[v];
        }
    }
    if(low[u]==dfn[u])
    {
        numb++;int counted=0;
        int cur;
       do
        {
            cur=sta.top();
            sta.pop();
            ins[cur]=0;
            scc[cur]=numb;
            counted++;
        }while(cur!=u);
        sccsize[numb]=counted;
    }
}
struct pi
{
    int id;
    int w;
};
bool my (pi a,pi b)
{
    if(a.w!=b.w)
      return a.w>b.w;
    else
      return a.id<b.id;
}
int sums=0;
vector<vector<int> >e2(maxv+1);
int ind[maxv];
void dfs(int u)
{
    for(int i=0;i<e2[u].size();i++)
    {
        int v=e2[u][i];
        if(!vis[v])
        {
            vis[v]=1;
            sums+=sccsize[v];
            dfs(v);
        }
    }
}
vector<int>sumss;
void solve()
{
    for(int i=0;i<n;i++)
   {
       if(!vis[i])
       {
           vis[i]=1;
           tarjan(i);
       }
   }
    for(int i=0;i<n;i++)
      for(int j=head[i];j!=-1;j=e[j][1])
      {
          int v=e[j][0];
          if(scc[i]!=scc[v])
         {
            e2[scc[v]].push_back(scc[i]);
            ind[scc[i]]++;
         }
      }
      int minsums=0;
      vector<pi>ans;
    for(int i=1;i<=numb;i++)
        {
            sums=0;
            memset(vis,0,sizeof(vis));
            if(ind[i]==0)
            {
                vis[i]=1;
                sums+=sccsize[i]-1;
                dfs(i);
              if(sums>=minsums)
              {
                  pi tp;
                  tp.w=sums;
                  tp.id=i;
                  ans.push_back(tp);
                  minsums=sums;
              }
            }
        }
        vector<int>realans;
       for(int i=0;i<ans.size();i++)
        {
            if(ans[i].w==minsums)
            {
                realans.push_back(ans[i].id);
            }
        }
    for(int j=0;j<realans.size();j++)
        for(int i=0;i<n;i++)
        {
            if(scc[i]==realans[j])
            {
                sumss.push_back(i);
            }
        }
     sort(sumss.begin(),sumss.end());
     printf("%d\n",minsums);
     for(int i=0;i<sumss.size();i++)
     {
          if(i!=sumss.size()-1)
              printf("%d ",sumss[i]);
          else
               printf("%d\n",sumss[i]);
     }
}
void read_build()
{
    int aa,bb,cc;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&aa,&bb);
        adde(aa,bb,0);
    }
}
void init()
{
    numb=times=nume=0;
    sumss.clear();
    for(int i=0;i<maxv;i++)
      {
          head[i]=-1;
          ins[i]=dfn[i]=low[i]=scc[i]=vis[i]=0;
          sccsize[i]=0;
          ind[i]=0;
          e2[i].clear();
      }
}
int main()
{
    int T;
    scanf("%d",&T);
    int ct=1;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        read_build();
        printf("Case %d: ",ct++);
        solve();
    }
    return 0;
}