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 ...
随机推荐
- iOS-xib(使用XIB自定义一个UIView )
1.新建一个xib视图
- POJ 2182
#include <iostream> #define MAXN 8005 using namespace std; int _m[MAXN]; int main() { //freope ...
- POJ 2141
#include<iostream> #include<stdio.h> using namespace std; int main() { //freopen("1 ...
- 关闭WordPress自动加载的Open Sans字体-WP访问过慢原因
序言 wordpress大概从wp-3.8开始会自动加载Open Sans字体,并引用Google上面的CSS样式.而最近谷歌经常打不开,导致网站访问速度过慢,严重的会拖慢几十秒.Open Sans字 ...
- Codeforces Round #336 (Div. 2)C. Chain Reaction DP
C. Chain Reaction There are n beacons located at distinct positions on a number line. The i-th bea ...
- UVALive 6187 Never Wait for Weights 带权并查集
题意:每次给出每两个数之间的大小差值.在给出关系的过程中插入询问:数a和数b的差值,若不能确定,输出UNKNOWN 解法:相对大小关系的处理:并查集 1.给出两点的相对大小关系后,找到两个点的根节点, ...
- 唉,还是Windows好
作为一个计算机专业的,常常抱怨Windows慢.一个系统用一段时间慢下来就重装,但是次次重装很麻烦,每次重装之后还得装软件. 另外,Windows比Linux占资源,所以前段时间就想以Linux为主要 ...
- Linux进程间通信(IPC)
序言 linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的. 而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心) ...
- TCP非阻塞accept和非阻塞connect
http://blog.chinaunix.net/uid-20751538-id-238260.html 非阻塞accept 当一个已完成的连接准备好被accept的时候,select会把监 ...
- 一个tomcat上放多个webapp问题,那这多个webapp会不会竞争端口呢?不会!安全两码事
1.一个tomcat上放多个webapp问题,那这多个webapp会不会竞争端口呢?不会!安全两码事