题意:有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. Java日志记录的事儿

    一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的 ...

  2. ZOJ3554 A Miser Boss(dp)

    给你n个工件,然后有A,B,C三个工厂,然后它们加工第i个工件所需要的时间分别为a[i],b[i],c[i],然后现在要你利用三间工厂加工所有的零件,要求是任何时间工厂都不能停工,而且一定要三间同时做 ...

  3. linux使用crontab实现PHP执行定时任务及codeiginter参数传递相关

    http://www.phpddt.com/php/linux-crontab.html crontab: yum install crontabs //安装 说明: /sbin/service cr ...

  4. linux 安装python,pip,

    Linux下python升级步骤 http://www.cnblogs.com/lanxuezaipiao/archive/2012/10/21/2732864.html 在 https://www. ...

  5. 安装Genymotion android模拟器

    Genymotion优点: 速度快性能好,资源占用低,系统要求512MB内存就能运行 支持 OpenGL 3D加速,可以流畅玩大型3D游戏 支持同时启动多个模拟器,可以实现软件或游戏多开 支持多种虚拟 ...

  6. lintcode: 生成括号

    生成括号 给定 n 对括号,请写一个函数以将其生成新的括号组合,并返回所有组合结果. 样例 给定 n = 3, 可生成的组合如下: "((()))", "(()())&q ...

  7. PHP 反射机制Reflection

    简介 PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类.方法.属性.参数等的详细信息,包括注释. class Reflection { } interface R ...

  8. 对所有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 ...

  9. Spring笔记——使用Spring进行面向切面(AOP)编程

    要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间: =================== Spring提供了两种切面声明方式,实际工作中我们可以选用其中一种: 1. 基于XM ...

  10. linux shell 命令学习(2) paste - merge lines of files

    paste - merge lines of files 命令格式: paste [OPTION] ... [FILE] ... 说明: 输出每个文件的对应行组合而成的行,中间用tab分开,如果没有F ...