hihoCoder #1179 : 永恒游戏 (暴力枚举)

 

题意:给出一个有n个点的无向图,每个点上有石头数个,现在的游戏规则是,设置某个点A的度数为d,如果A点的石子数大于等于d,则可以从A点给每个邻接点发一个石子。如果游戏可以玩10万次以上,输出INF,否则输出最多能玩几次。

思路:暴力枚举每个可以玩的点,假如可以玩无限次,且当前状态为Z(指所有点的石头数的序列作为一个状态),那么在玩了多次之后,一定会造成循环,也就是说,玩几次之后,每个点的石子数和初始的石子数一模一样,这样子我再重复之前是怎么玩的就可以无限玩了。但是由于有200个点,所以玩一次就去判断是否和初始一样的状态,否则复杂度为 O(100000*结点数*该结点的边数),数量级上亿。

现在只需要枚举10万次就知道结果了,不用去判断其他的。而且每次选择要玩的点都可以任意选,只要满足了条件(并不需要先玩石子数多的,或少的)。

 

 1 #include <bits/stdc++.h>

 2 #define LL long long

 3 using namespace std;

 4 const int N=205;

 5 int n, m, a, b, num[N];

 6 vector< vector<int> >   vect;

 7 unordered_set<int> sett;

 8 

 9 int cal()

10 {

11     int cnt=0;

12     for(int i=0; i<n; i++)    if(num[i]>=vect[i].size())    sett.insert(i);    //符合条件

13     while(!sett.empty())

14     {

15         cnt++;              //一次

16         if(cnt>=100000) return cnt;

17         int q=*sett.begin();

18         num[q]-=vect[q].size();

19         if(num[q]<vect[q].size())  sett.erase(sett.begin()); //这个点已经不能再玩了

20 

21         for(int i=0; i<vect[q].size(); i++) //往邻居加石头

22         {

23             int p=vect[q][i];  //栈顶结点所连的点

24             num[p]++;

25             if(num[p]>=vect[p].size() ) sett.insert(p);

26         }

27     }

28     return cnt;

29 }

30 

31 int main()

32 {

33     //freopen("e://input.txt", "r", stdin);

34     scanf("%d%d",&n,&m);

35     for(int i=0; i<n; i++) scanf("%d", &num[i]); //石头数

36     vect.resize(n);

37     for(int i=0; i<m; i++)

38     {

39         scanf("%d%d", &a, &b);    //输入边,无向图

40         vect[a].push_back(b);

41         vect[b].push_back(a);

42     }

43 

44     int ans=cal();

45     if(ans>=100000)     printf("INF\n");

46     else                printf("%d\n",ans);

47 

48     return 0;

49 }
AC代码

 

你可能感兴趣的:(code)