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 ...
随机推荐
- Java日志记录的事儿
一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的 ...
- ZOJ3554 A Miser Boss(dp)
给你n个工件,然后有A,B,C三个工厂,然后它们加工第i个工件所需要的时间分别为a[i],b[i],c[i],然后现在要你利用三间工厂加工所有的零件,要求是任何时间工厂都不能停工,而且一定要三间同时做 ...
- linux使用crontab实现PHP执行定时任务及codeiginter参数传递相关
http://www.phpddt.com/php/linux-crontab.html crontab: yum install crontabs //安装 说明: /sbin/service cr ...
- linux 安装python,pip,
Linux下python升级步骤 http://www.cnblogs.com/lanxuezaipiao/archive/2012/10/21/2732864.html 在 https://www. ...
- 安装Genymotion android模拟器
Genymotion优点: 速度快性能好,资源占用低,系统要求512MB内存就能运行 支持 OpenGL 3D加速,可以流畅玩大型3D游戏 支持同时启动多个模拟器,可以实现软件或游戏多开 支持多种虚拟 ...
- lintcode: 生成括号
生成括号 给定 n 对括号,请写一个函数以将其生成新的括号组合,并返回所有组合结果. 样例 给定 n = 3, 可生成的组合如下: "((()))", "(()())&q ...
- PHP 反射机制Reflection
简介 PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类.方法.属性.参数等的详细信息,包括注释. class Reflection { } interface R ...
- 对所有CPU寄存器的简述(16位CPU14个,32位CPU16个)
32位CPU所含有的寄存器有:4个数据寄存器(EAX.EBX.ECX和EDX)2个变址和指针寄存器(ESI和EDI)2个指针寄存器(ESP和EBP)6个段寄存器(ES.CS.SS.DS.FS和GS)1 ...
- Spring笔记——使用Spring进行面向切面(AOP)编程
要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间: =================== Spring提供了两种切面声明方式,实际工作中我们可以选用其中一种: 1. 基于XM ...
- linux shell 命令学习(2) paste - merge lines of files
paste - merge lines of files 命令格式: paste [OPTION] ... [FILE] ... 说明: 输出每个文件的对应行组合而成的行,中间用tab分开,如果没有F ...