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了。坑~~~~耗费我几小时青春。
#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 糖果分配(模拟,图)的更多相关文章
- 2015多校第6场 HDU 5353 Average 贪心,细节处理
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5353 题意:有n个人围城一个环,每一个人手里都有一些糖果,第i个人有ai块.现在有三种操作:第i个人给 ...
- HDU 5353—— Average——————【贪心+枚举】
Average Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total S ...
- HDU 5353 Average
Problem Description There are n soda sitting around a round table. soda are numbered from 1 to n and ...
- HDU 5353 Average 贪心
就是贪心啊,不知道为啥总是不过,总是WA 方法不对吗? 将数组扩展一倍,从左到右扫描,大于平均数就给右边的,小于就从右边拿,等于就不变,记录下操作类型. 大于2直接NO,不知道哪错了,自己出了一些数据 ...
- HDU 4041 Eliminate Witches! (模拟题 ACM ICPC 2011亚洲北京赛区网络赛)
HDU 4041 Eliminate Witches! (模拟题 ACM ICPC 2011 亚洲北京赛区网络赛题目) Eliminate Witches! Time Limit: 2000/1000 ...
- 思维/构造 HDOJ 5353 Average
题目传送门 /* 思维/构造:赛后补的,当时觉得3题可以交差了,没想到这题也是可以做的.一看到这题就想到了UVA_11300(求最小交换数) 这题是简化版,只要判断行不行和行的方案就可以了,做法是枚举 ...
- HDU 1034(传递糖果 模拟)
题意是一群孩子围成一个圈,每个人把手中的糖果分一半给右边的人,若分过之后手中的糖果数是奇数,则由老师提供一颗糖果给他,问这样传递多少圈所有人的糖果数都能相等,最终每人手里的糖果数是多少. 由于题中已经 ...
- 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 ...
- POJ 1308&&HDU 1272 并查集判断图
HDU 1272 I - 小希的迷宫 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64 ...
随机推荐
- JavaScript call和apply的用法
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- POJ 1027 The Same Game(模拟)
题目链接 题意 : 一个10×15的格子,有三种颜色的球,颜色相同且在同一片内的球叫做cluster(具体解释就是,两个球颜色相同且一个球可以通过上下左右到达另一个球,则这两个球属于同一个cluste ...
- ExtJs布局之table
<!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...
- MONO常用快捷键
Action Mac OS X Win/Linux 注释代码(//) Cmd + / Ctrl + / 注释代码(/**/) Cmd + Option + / Ctrl + Shift + / 格 ...
- Spring学习总结(0)——Spring详解
一:spring的基本用法: 1,关于spring容器: spring容器是Spring的核心,该 容器负责管理spring中的java组件, ApplicationContext ctx = ne ...
- iOS 开发--添加工程
文/Bison(简书作者)原文链接:http://www.jianshu.com/p/dd71e15df5d0著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 第一部分,配置项目 在此只 ...
- 根据ip查询地区,经纬度等-geoip2
这项工作难度主要在数据上,数据越准确越有利. 1. 下载数据文件: http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.m ...
- python urllib2的proxyhandler
1. 再a方法中新建了个opener,使用了代理: proxydict = {} proxydict['http'] = "http://%s:%s"%(ip,port) #pri ...
- JavaScript一些关键概念
垃圾回收:http://www.cnblogs.com/dolphinX/p/3348468.html 引用计数和标记清除 作用链和闭包:http://www.cnblogs.com/dolphinX ...
- B/S和C/S的区别
B/S 指的是 Browser/Server : C/S 指的是Client/Server 区别: 1. B/S最大优势为客户端免维护,适用于用户群庞大,或客户需求经长发生变化的情况. C/S功能强大 ...