zoukankan      html  css  js  c++  java
  • HDU 5353 Average 糖果分配(模拟,图)

    题意:有n个人坐在圆桌上,每个人带着糖果若干,每次只能给旁边的人1科糖果,而且坐相邻的两个人最多只能给一次(要么你给我,要么我给你),问是否能将糖果平均分了。

    思路:

      明显每个人最多只能多于平均值2个糖果,因为他只能分别往左和右边的人给1颗。而多于平均值1的人可以任意选1个方向,只要到最后所有人满足了即可。多余糖果超过3的、平均数是浮点型的都是无解。

      求解步骤:

      在第i和第i+1个人之间建两条边(即无向边拆成2条有向边),分别从一方指向另一方。1和n也建两条。分两步:

      (1)将持有2个多余糖果的人先处理,用DFS分别向左边和右边各深搜1次,直到遇到缺糖的人,只能成功,且要标记走过的路径(直接封掉这些无向边,即两条有向边)。

      (2)将持有1个多余糖果的人先左边尝试给别人糖果,遇到标记的边则返回(路已经被走过了),从另一个方向尝试给别人糖果。

      如果有任何一步失败,则无解。若以上都成功了,那么糖果就能成功平均分配。

      但是可能会将两条边都同时标记了,那么他们互相抵消了,比如3 1 1 3 四个人。那么如果,1沿着1-2-3给了3一个糖果,而4沿着4->3>2给了2一个糖果,那么就成功了,而他们走过的边也互相抵消了,即2-3和3-2抵消了,相当于1只走到2,而4只走到3。这一步只需要在输出答案时处理一下即可。

       终于AC了 !~~~   上面提到的,属于同一条无向边的拆成而来的两条有向边,若同时被标记了(即都被送糖果的人走过了),那么要及时将这两条边抹去标记,恢复为可行状态。其他的人才可以继续通行这些路。只是实在想不出恢复与不恢复的区别,只是恢复了就AC了。坑~~~~耗费我几小时青春。

      1 #include <bits/stdc++.h>
      2 #define INF 0x7f7f7f7f
      3 #define pii pair<int,int>
      4 #define LL long long
      5 using namespace std;
      6 const int N=101000;
      7 struct node
      8 {
      9     int from,to;
     10     bool vis;
     11     node(){};
     12     node(int from,int to,bool vis):from(from), to(to), vis(vis){};
     13 }edge[N*5];
     14 int edge_cnt, candy[N], even;
     15 vector<int> vect[N];
     16 vector<pii> ans;
     17 
     18 void add_node(int from,int to)
     19 {
     20     edge[edge_cnt]=node(from, to, 0);
     21     vect[from].push_back(edge_cnt++);
     22 }
     23 
     24 bool cansolve(int n, LL sum)    //是否有解
     25 {
     26     if(sum%n)    return false;
     27     for(int i=1; i<=n; i++)    if( abs(candy[i]-even )>2 ) return false;    //超过了2,只有两条边,不可能!
     28     return true;
     29 }
     30 
     31 bool DFS(int s,int far,int flag)    //注:far是为了让深搜时不能走回头。处理1时可忽略(任一方向皆可)。
     32 {
     33     if(candy[s]<even)
     34     {
     35         candy[s]++;         //给它
     36         return true;
     37     }
     38 
     39     for(int i=0; i<vect[s].size(); i++)
     40     {
     41         int t=vect[s][i];
     42         if(!edge[t].vis && edge[t].to!=far)
     43         {
     44             edge[t].vis=1;
     45             if(DFS(edge[t].to, s, flag))
     46             {
     47                 if(flag)
     48                 {
     49                     edge[t^1].vis=1;    //对于2的,一旦走过,直接封掉"后悔边"。
     50                     ans.push_back( make_pair(edge[t].from, edge[t].to) );//因为输出答案的关系,这里要先提交答案
     51                 }
     52                 if(!flag&&edge[t^1].vis)
     53                     edge[t].vis=edge[t^1].vis=0;    //重点在这里,如果抵消了,要及时将被抵消边恢复为可行。
     54                 return true;
     55             }
     56             edge[t].vis=0;  //此方向无解,还原路径。
     57         }
     58     }
     59     return false;
     60 }
     61 
     62 int cal(int n)
     63 {
     64     LL sum=0;
     65     for(int i=1; i<=n; i++)  sum+=candy[i];
     66     even=sum/n;
     67     if( !cansolve(n, sum) ) //判断是否有解
     68     {
     69         printf("NO
    ");
     70         return 0;
     71     }
     72 
     73     for(int i=1; i<=n; i++) //建边
     74     {
     75         add_node(i, i%n+1 );
     76         add_node(i%n+1, i);
     77     }
     78 
     79 
     80     for(int i=1; i<=n; i++) //处理多余2的
     81     {
     82         if(candy[i]-even==2)
     83         {
     84             candy[i]=even;
     85             if(!DFS(i, (i+1)%n+1, 1) || !DFS(i, (n+i-1)%n+1, 1) ) //加个far是为了让它不能走回头
     86             {
     87                 printf("NO
    ");     //只要有一个不ok,都是不行。
     88                 return 0;
     89             }
     90         }
     91     }
     92 
     93     for(int i=1; i<=n; i++) //处理多余1的
     94     {
     95         if(candy[i]-even==1 )
     96         {
     97             candy[i]=even;
     98             if( !DFS(i, -1, 0)   )    //far为-1就是可以让DFS往两个方向都尝试。
     99             {
    100                 printf("NO
    "); //任一方向都给不出去,无解。
    101                 return false;
    102             }
    103         }
    104     }
    105     return true;
    106 }
    107 
    108 int main()
    109 {
    110     freopen("input.txt", "r", stdin);
    111     int t, n;
    112     cin>>t;
    113     while(t--)
    114     {
    115         scanf("%d",&n);
    116         for(int i=1; i<=n; i++)    vect[i].clear();
    117         for(int i=1; i<=n; i++)    scanf("%d", &candy[i]);
    118         edge_cnt=0;
    119         ans.clear();
    120         if(n==2)
    121         {
    122             if(candy[1]==candy[2])  printf("YES
    0
    ");
    123             else if( abs(candy[1]-candy[2])==2 )
    124             {
    125                 printf("YES
    1
    ");
    126                 if( candy[1]>candy[2])    printf("1 2
    ");
    127                 else    printf("2 1
    ");
    128             }
    129             else    puts("NO");
    130             continue;
    131         }
    132 
    133 
    134         if(cal(n))
    135         {
    136             for(int i=0; i<edge_cnt; i+=2)
    137             {
    138                 if( edge[i].vis && edge[i+1].vis )    continue; //抵消了,或者是处理2的时候被封的。
    139                 if( edge[i].vis )    ans.push_back( make_pair(edge[i].from,   edge[i].to)  );
    140                 if( edge[i+1].vis )  ans.push_back( make_pair(edge[i+1].from, edge[i+1].to));
    141             }
    142             printf("YES
    %d
    ", ans.size());
    143             for(int i=0; i<ans.size(); i++)    printf("%d %d
    ", ans[i].first, ans[i].second );
    144         }
    145 
    146     }
    147     return 0;
    148 }
    AC代码
      1 #include <bits/stdc++.h>
      2 #define INF 0x7f7f7f7f
      3 #define pii pair<int,int>
      4 #define LL long long
      5 using namespace std;
      6 const int N=101000;
      7 struct node
      8 {
      9     int from,to;
     10     bool vis;
     11     node(){};
     12     node(int from,int to,bool vis):from(from), to(to), vis(vis){};
     13 }edge[N*20];
     14 int edge_cnt, candy[N], even;
     15 vector<int> vect[N];
     16 
     17 
     18 void add_node(int from,int to)
     19 {
     20     edge[edge_cnt]=node(from, to, 0);
     21     vect[from].push_back(edge_cnt++);
     22 }
     23 
     24 bool cansolve(int n, LL sum)    //是否有解
     25 {
     26     if(sum%n>0)    return false;
     27     for(int i=1; i<=n; i++)    if( abs(candy[i]-even )>2 ) return false;
     28     return true;
     29 }
     30 
     31 bool DFS(int s,int far)
     32 {
     33     if(candy[s]<even)
     34     {
     35         candy[s]++;
     36         return true;
     37     }
     38 
     39     for(int i=0; i<vect[s].size(); i++)
     40     {
     41         int t=vect[s][i];
     42         if(!edge[t].vis && edge[t].to!=far)
     43         {
     44             edge[t].vis=1;
     45             if(DFS(edge[t].to, s)) return true;
     46             edge[t].vis=0;  //不成功,抹去标记
     47         }
     48     }
     49     return false;
     50 }
     51 
     52 int cal(int n)
     53 {
     54     LL sum=0;
     55     for(int i=1; i<=n; i++)  sum+=candy[i];
     56     even=sum/n;
     57     if( !cansolve(n, sum) )
     58     {
     59         printf("NO
    ");
     60         return 0;
     61     }
     62     add_node(n, 1);//建图
     63     add_node(1, n);
     64     for(int i=1; i<n; i++)
     65     {
     66         add_node(i, i+1);
     67         add_node(i+1, i);
     68     }
     69 
     70 
     71     for(int i=1; i<=n; i++) //处理多2的
     72     {
     73         if(candy[i]-even==2)
     74         {
     75             candy[i]=even;
     76             if(!DFS(i, i+1) || !DFS(i, i-1) )
     77             {
     78                 printf("NO
    ");
     79                 return 0;
     80             }
     81         }
     82     }
     83 
     84     for(int i=1; i<=n; i++) //处理多1的
     85     {
     86         if(candy[i]-even==1 )
     87         {
     88             candy[i]=even;
     89             if( !DFS(i, -1)   )
     90             {
     91                 printf("NO
    ");
     92                 return false;
     93             }
     94         }
     95     }
     96     for(int i=1; i<=n; i++) 
     97     {
     98         if(candy[i]!=even )//不能平均分配
     99         {
    100             printf("NO
    ");
    101             return false;
    102         }
    103     }
    104     return true;
    105 }
    106 
    107 vector<pii> ans;
    108 
    109 int main()
    110 {
    111     freopen("input.txt", "r", stdin);
    112     int t, n;
    113     cin>>t;
    114     while(t--)
    115     {
    116         scanf("%d",&n);
    117         for(int i=1; i<=n; i++)    vect[i].clear();
    118 
    119         for(int i=1; i<=n; i++)    scanf("%d", &candy[i]);
    120         edge_cnt=0;
    121 
    122         if(n==1)//特判
    123         {
    124             printf("YES
    0
    ");
    125             continue;
    126         }
    127         else if(n==2)
    128         {
    129             if(candy[1]==candy[2])  printf("YES
    0
    ");
    130             else if( abs(candy[1]-candy[2])==2 )
    131             {
    132                 printf("YES
    1
    ");
    133                 if( candy[1]>candy[2])    printf("1 2
    ");
    134                 else    printf("2 1
    ");
    135             }
    136             else    puts("NO");
    137             continue;
    138         }
    139 
    140 
    141         if(cal(n))
    142         {
    143             ans.clear();
    144             for(int i=0; i<edge_cnt; i+=2)
    145             {
    146                 if( edge[i].vis && edge[i+1].vis )    continue; //抵消了
    147                 if( edge[i].vis )    ans.push_back( make_pair(edge[i].from,   edge[i].to)  );
    148                 if( edge[i+1].vis )  ans.push_back( make_pair(edge[i+1].from, edge[i+1].to));
    149             }
    150             printf("YES
    %d
    ", ans.size());
    151             for(int i=0; i<ans.size(); i++)    printf("%d %d
    ", ans[i].first, ans[i].second );
    152         }
    153     }
    154     return 0;
    155 }
    WA代码
  • 相关阅读:
    UVa 481
    ZOJ 1108 & HDU 1160
    UVa 11450
    UVa 11242
    UVa 750
    UVa 725
    UVa 483
    UVa 10258
    UVa 793
    The Little Girl who Picks Mushrooms HDU 4422 水题类似模拟的一种感觉
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4709310.html
Copyright © 2011-2022 走看看