HDU 5876 Sparse Graph

题目:Sparse Graph

链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5876

题意:给出一个图(V<=20万,E<=2万),要求先化为补图(每两个点,原本有边删去边,原本没边添加边),然后问指定点S到其他每个点的最短距离。

思路:

  普通的广搜应该解决不了。。。O(n*m)太大,不会很难,比赛时没做出来有点可惜,当知道过了也进不了时,就安慰了许多。

  变化一下思路,从起点出发,因为原本边<=2万,那么大部分的点都已经可以到达了,也就是len=1(len最短距离),现在用集合st 来存放还没到达的点,用ad[i]=true来表示i 已经到达,用co表示已经到达的点的数量。每一次循环遍历st,对于某一个还没到达的点x ,假定和x 相邻的点有m 个,如果m<co,那说明x 肯定能到达。因为原本y 和x 没有边,补图里肯定就有,也就是说最坏情况是m个点对应的都是已经遍历过的,那么co-m这些点肯定能到达x。如果m>=co,并不能说明x 一定到不了,现在就要遍历m个点,如果某个点是没有遍历过的,m可以-1,如果最终m<co,说明x 还是可以遍历到的。每一次循环,就是找出若干个x ,x能到达,如果没有这样的x 就可以退出了,如果有,集合删去这些x,记录len,记录ad,记录co ,进入下次循环。

  时间复杂度计算:集合最初最多2万个点,每次删掉就不恢复了,这里的时间为E,m>=co要找点时也就是遍历所有的边,每个边最多遍历1次,时间E。也就是说循环里看似套了很多层,其实很快,外面大概就是V,时间复杂度V+E。

AC代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<math.h>
  5 #include<set>
  6 #include<map>
  7 #include<list>
  8 #include<stack>
  9 #include<queue>
 10 #include<vector>
 11 #include<string>
 12 #include<iostream>
 13 #include<algorithm>
 14 using namespace std;
 15 #define lson rt<<1
 16 #define rson rt<<1|1
 17 #define N 200010
 18 #define M 100010
 19 #define Mod 1000000007
 20 #define LL long long
 21 #define INF 0x7fffffff
 22 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++)
 23 #define For(i,f_start,f_end) for(int i=f_start;i<f_end;i++)
 24 #define REP(i,f_end,f_start) for(int i=f_end;i>=f_start;i--)
 25 #define Rep(i,f_end,f_start) for(int i=f_end;i>f_start;i--)
 26 #define MT(x,i) memset(x,i,sizeof(x))
 27 #define gcd(x,y) __gcd(x,y)
 28 const double PI = acos(-1);
 29 
 30 bool ad[N];
 31 int len[N];
 32 vector<int> v[N];
 33 vector<int> zan;
 34 set<int> st;
 35 int main()
 36 {
 37   int t,n,m,x,y;
 38   scanf("%d",&t);
 39   while(t--)
 40   {
 41     scanf("%d%d",&n,&m);
 42     while(m--)
 43     {
 44       scanf("%d%d",&x,&y);
 45       v[x].push_back(y);
 46       v[y].push_back(x);
 47     }
 48     int s,co=1;
 49     scanf("%d",&s);
 50     st.clear();
 51     MT(ad,0);
 52     ad[s]=true;
 53     For(i,0,v[s].size()){
 54       ad[v[s][i]]=true;
 55     }
 56 
 57     MT(len,-1);
 58     FOR(i,1,n){
 59       if(i==s) continue;
 60       if(ad[i]==false){
 61         len[i]=1;
 62         co++;
 63         ad[i]=true;
 64       }
 65       else{
 66         st.insert(i);
 67         ad[i]=false;
 68       }
 69     }
 70     int ll=2;
 71     while(1)
 72     {
 73       zan.clear();
 74       bool ff=false;
 75       for(set<int>::iterator it=st.begin();it!=st.end();it++)
 76       {
 77         int x=*it;
 78         bool flag=false;
 79         if(v[x].size()<co)
 80         {
 81           flag=true;
 82         }
 83         else
 84         {
 85           int k=v[x].size();
 86           For(i,0,v[x].size())
 87           {
 88             int son=v[x][i];
 89             if(ad[son]==false) k--;
 90             if(k<co) break;
 91           }
 92           if(k<co)
 93           {
 94             flag=true;
 95           }
 96         }
 97         if(flag==true)
 98         {
 99           ff=true;
100           zan.push_back(x);
101         }
102       }
103       if(ff==false) break;
104       For(i,0,zan.size())
105       {
106         ad[zan[i]]=true;
107         len[zan[i]]=ll;
108         co++;
109       }
110       ll++;
111       for(set<int>::iterator it=st.begin();it!=st.end();)
112       {
113         int x=*it;
114         if(ad[x]==true) st.erase(it++);
115         else it++;
116       }
117     }
118     bool ff=false;
119     FOR(i,1,n){
120       if(i!=s){
121         if(ff!=false) printf(" ");
122         else ff=true;
123         printf("%d",len[i]);
124       }
125     }
126     printf("\n");
127     FOR(i,1,n){
128       v[i].clear();
129     }
130   }
131   return 0;
132 }
posted @ 2016-09-10 22:54  hchlqlz  阅读(428)  评论(0编辑  收藏  举报