题意:有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了。坑~~~~耗费我几小时青春。

 #include <bits/stdc++.h>
#define INF 0x7f7f7f7f
#define pii pair<int,int>
#define LL long long
using namespace std;
const int N=;
struct node
{
int from,to;
bool vis;
node(){};
node(int from,int to,bool vis):from(from), to(to), vis(vis){};
}edge[N*];
int edge_cnt, candy[N], even;
vector<int> vect[N];
vector<pii> ans; void add_node(int from,int to)
{
edge[edge_cnt]=node(from, to, );
vect[from].push_back(edge_cnt++);
} bool cansolve(int n, LL sum) //是否有解
{
if(sum%n) return false;
for(int i=; i<=n; i++) if( abs(candy[i]-even )> ) return false; //超过了2,只有两条边,不可能!
return true;
} bool DFS(int s,int far,int flag) //注:far是为了让深搜时不能走回头。处理1时可忽略(任一方向皆可)。
{
if(candy[s]<even)
{
candy[s]++; //给它
return true;
} for(int i=; i<vect[s].size(); i++)
{
int t=vect[s][i];
if(!edge[t].vis && edge[t].to!=far)
{
edge[t].vis=;
if(DFS(edge[t].to, s, flag))
{
if(flag)
{
edge[t^].vis=; //对于2的,一旦走过,直接封掉"后悔边"。
ans.push_back( make_pair(edge[t].from, edge[t].to) );//因为输出答案的关系,这里要先提交答案
}
if(!flag&&edge[t^].vis)
edge[t].vis=edge[t^].vis=; //重点在这里,如果抵消了,要及时将被抵消边恢复为可行。
return true;
}
edge[t].vis=; //此方向无解,还原路径。
}
}
return false;
} int cal(int n)
{
LL sum=;
for(int i=; i<=n; i++) sum+=candy[i];
even=sum/n;
if( !cansolve(n, sum) ) //判断是否有解
{
printf("NO\n");
return ;
} for(int i=; i<=n; i++) //建边
{
add_node(i, i%n+ );
add_node(i%n+, i);
} for(int i=; i<=n; i++) //处理多余2的
{
if(candy[i]-even==)
{
candy[i]=even;
if(!DFS(i, (i+)%n+, ) || !DFS(i, (n+i-)%n+, ) ) //加个far是为了让它不能走回头
{
printf("NO\n"); //只要有一个不ok,都是不行。
return ;
}
}
} for(int i=; i<=n; i++) //处理多余1的
{
if(candy[i]-even== )
{
candy[i]=even;
if( !DFS(i, -, ) ) //far为-1就是可以让DFS往两个方向都尝试。
{
printf("NO\n"); //任一方向都给不出去,无解。
return false;
}
}
}
return true;
} int main()
{
freopen("input.txt", "r", stdin);
int t, n;
cin>>t;
while(t--)
{
scanf("%d",&n);
for(int i=; i<=n; i++) vect[i].clear();
for(int i=; i<=n; i++) scanf("%d", &candy[i]);
edge_cnt=;
ans.clear();
if(n==)
{
if(candy[]==candy[]) printf("YES\n0\n");
else if( abs(candy[]-candy[])== )
{
printf("YES\n1\n");
if( candy[]>candy[]) printf("1 2\n");
else printf("2 1\n");
}
else puts("NO");
continue;
} if(cal(n))
{
for(int i=; i<edge_cnt; i+=)
{
if( edge[i].vis && edge[i+].vis ) continue; //抵消了,或者是处理2的时候被封的。
if( edge[i].vis ) ans.push_back( make_pair(edge[i].from, edge[i].to) );
if( edge[i+].vis ) ans.push_back( make_pair(edge[i+].from, edge[i+].to));
}
printf("YES\n%d\n", ans.size());
for(int i=; i<ans.size(); i++) printf("%d %d\n", ans[i].first, ans[i].second );
} }
return ;
}

AC代码

 #include <bits/stdc++.h>
#define INF 0x7f7f7f7f
#define pii pair<int,int>
#define LL long long
using namespace std;
const int N=;
struct node
{
int from,to;
bool vis;
node(){};
node(int from,int to,bool vis):from(from), to(to), vis(vis){};
}edge[N*];
int edge_cnt, candy[N], even;
vector<int> vect[N]; void add_node(int from,int to)
{
edge[edge_cnt]=node(from, to, );
vect[from].push_back(edge_cnt++);
} bool cansolve(int n, LL sum) //是否有解
{
if(sum%n>) return false;
for(int i=; i<=n; i++) if( abs(candy[i]-even )> ) return false;
return true;
} bool DFS(int s,int far)
{
if(candy[s]<even)
{
candy[s]++;
return true;
} for(int i=; i<vect[s].size(); i++)
{
int t=vect[s][i];
if(!edge[t].vis && edge[t].to!=far)
{
edge[t].vis=;
if(DFS(edge[t].to, s)) return true;
edge[t].vis=; //不成功,抹去标记
}
}
return false;
} int cal(int n)
{
LL sum=;
for(int i=; i<=n; i++) sum+=candy[i];
even=sum/n;
if( !cansolve(n, sum) )
{
printf("NO\n");
return ;
}
add_node(n, );//建图
add_node(, n);
for(int i=; i<n; i++)
{
add_node(i, i+);
add_node(i+, i);
} for(int i=; i<=n; i++) //处理多2的
{
if(candy[i]-even==)
{
candy[i]=even;
if(!DFS(i, i+) || !DFS(i, i-) )
{
printf("NO\n");
return ;
}
}
} for(int i=; i<=n; i++) //处理多1的
{
if(candy[i]-even== )
{
candy[i]=even;
if( !DFS(i, -) )
{
printf("NO\n");
return false;
}
}
}
for(int i=; i<=n; i++)
{
if(candy[i]!=even )//不能平均分配
{
printf("NO\n");
return false;
}
}
return true;
} vector<pii> ans; int main()
{
freopen("input.txt", "r", stdin);
int t, n;
cin>>t;
while(t--)
{
scanf("%d",&n);
for(int i=; i<=n; i++) vect[i].clear(); for(int i=; i<=n; i++) scanf("%d", &candy[i]);
edge_cnt=; if(n==)//特判
{
printf("YES\n0\n");
continue;
}
else if(n==)
{
if(candy[]==candy[]) printf("YES\n0\n");
else if( abs(candy[]-candy[])== )
{
printf("YES\n1\n");
if( candy[]>candy[]) printf("1 2\n");
else printf("2 1\n");
}
else puts("NO");
continue;
} if(cal(n))
{
ans.clear();
for(int i=; i<edge_cnt; i+=)
{
if( edge[i].vis && edge[i+].vis ) continue; //抵消了
if( edge[i].vis ) ans.push_back( make_pair(edge[i].from, edge[i].to) );
if( edge[i+].vis ) ans.push_back( make_pair(edge[i+].from, edge[i+].to));
}
printf("YES\n%d\n", ans.size());
for(int i=; i<ans.size(); i++) printf("%d %d\n", ans[i].first, ans[i].second );
}
}
return ;
}

WA代码

HDU 5353 Average 糖果分配(模拟,图)的更多相关文章

  1. 2015多校第6场 HDU 5353 Average 贪心,细节处理

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5353 题意:有n个人围城一个环,每一个人手里都有一些糖果,第i个人有ai块.现在有三种操作:第i个人给 ...

  2. HDU 5353—— Average——————【贪心+枚举】

    Average Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total S ...

  3. HDU 5353 Average

    Problem Description There are n soda sitting around a round table. soda are numbered from 1 to n and ...

  4. HDU 5353 Average 贪心

    就是贪心啊,不知道为啥总是不过,总是WA 方法不对吗? 将数组扩展一倍,从左到右扫描,大于平均数就给右边的,小于就从右边拿,等于就不变,记录下操作类型. 大于2直接NO,不知道哪错了,自己出了一些数据 ...

  5. HDU 4041 Eliminate Witches! (模拟题 ACM ICPC 2011亚洲北京赛区网络赛)

    HDU 4041 Eliminate Witches! (模拟题 ACM ICPC 2011 亚洲北京赛区网络赛题目) Eliminate Witches! Time Limit: 2000/1000 ...

  6. 思维/构造 HDOJ 5353 Average

    题目传送门 /* 思维/构造:赛后补的,当时觉得3题可以交差了,没想到这题也是可以做的.一看到这题就想到了UVA_11300(求最小交换数) 这题是简化版,只要判断行不行和行的方案就可以了,做法是枚举 ...

  7. HDU 1034(传递糖果 模拟)

    题意是一群孩子围成一个圈,每个人把手中的糖果分一半给右边的人,若分过之后手中的糖果数是奇数,则由老师提供一颗糖果给他,问这样传递多少圈所有人的糖果数都能相等,最终每人手里的糖果数是多少. 由于题中已经 ...

  8. HDU 5873 Football Games 【模拟】 (2016 ACM/ICPC Asia Regional Dalian Online)

    Football Games Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  9. POJ 1308&&HDU 1272 并查集判断图

      HDU 1272 I - 小希的迷宫 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64 ...

随机推荐

  1. JavaScript call和apply的用法

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  2. POJ 1027 The Same Game(模拟)

    题目链接 题意 : 一个10×15的格子,有三种颜色的球,颜色相同且在同一片内的球叫做cluster(具体解释就是,两个球颜色相同且一个球可以通过上下左右到达另一个球,则这两个球属于同一个cluste ...

  3. ExtJs布局之table

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  4. MONO常用快捷键

      Action Mac OS X Win/Linux 注释代码(//) Cmd + / Ctrl + / 注释代码(/**/) Cmd + Option + / Ctrl + Shift + / 格 ...

  5. Spring学习总结(0)——Spring详解

    一:spring的基本用法: 1,关于spring容器: spring容器是Spring的核心,该 容器负责管理spring中的java组件, ApplicationContext ctx  = ne ...

  6. iOS 开发--添加工程

    文/Bison(简书作者)原文链接:http://www.jianshu.com/p/dd71e15df5d0著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 第一部分,配置项目 在此只 ...

  7. 根据ip查询地区,经纬度等-geoip2

    这项工作难度主要在数据上,数据越准确越有利. 1. 下载数据文件: http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.m ...

  8. python urllib2的proxyhandler

    1. 再a方法中新建了个opener,使用了代理: proxydict = {} proxydict['http'] = "http://%s:%s"%(ip,port) #pri ...

  9. JavaScript一些关键概念

    垃圾回收:http://www.cnblogs.com/dolphinX/p/3348468.html 引用计数和标记清除 作用链和闭包:http://www.cnblogs.com/dolphinX ...

  10. B/S和C/S的区别

    B/S 指的是 Browser/Server : C/S 指的是Client/Server 区别: 1. B/S最大优势为客户端免维护,适用于用户群庞大,或客户需求经长发生变化的情况. C/S功能强大 ...