[POI2008]枪战Maf题解
问题 C: [POI2008]枪战Maf
时间限制: 1 Sec 内存限制: 256 MB
题目描述
有n个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。因此,对于不同的开枪顺序,最后死的人也不同。
输入
输入n人数<1000000 每个人的aim
输出
你要求最后死亡数目的最小和最大可能
样例输入
8
2 3 2 2 6 7 8 5
样例输出
3 5
本次考试最后一个题,被老师评论称难炸了……然而貌似不那么难,但你绝对打不A。
这道题只能怪我代码能力太弱,该想到的都想到了,然而还是华丽丽的爆了0。
首先让我们先明确几条性质来帮助我们做题:
- 对于每个连通图,他至少有一个环或者一个人自杀。缩完点之后它是树或树林。证明:假设我们已经输入了n个人,先忽略一下第n个人要杀谁,如果之前没有人自杀或环的话它一定是一棵树,因为有n个点和n-1条边,那么第n个人指向哪里就很关键了,他指向每一个其他人都会形成一个环,而指向他自己又是自杀,所以,第一条get。
- 每一个没人杀的人都会存活,每一个自杀的人最终都会死。不解释。
- 每个人对于答案的影响不在于他被谁杀掉,而在于他杀掉谁,世界不关心你说了什么,世界只关心你做了什么。
- 一个环如果没人干预,那么它最少死n/2个人,向下取整。也就是一个人如果不杀人就只能被杀死,对于奇数个点的环你杀了人也可能被杀死。最多就是总人数-1。
- 一个环如果有人干预,那么它最多就是全部被杀,最小在下面说。
- 如果一个人没死,那么他指向的那个人就一定会死,如果指向那个人的人都死了,那么他就可以活下来,这一点在环中同样适用。
为了方便,我们直接去求活着的人数,反正人不是活着就是死了废话。
先说死的人最少,那么入度为0的人一定活下来了,因此我们用队列慢慢往上爬即可,只要队列中的人他所杀的人要杀的人没人杀他了,那么他也可以入队。至于没人指向的环嘛,上面说了。
死的最多的人就是让人们从树顶从上往下开枪,直到叶子节点所以答案就为缩完点后入度为0的点。
我打完之后只过了一个点,因为这题有两个坑点,至少对我来说是这样的。
第一,指向这个点的点可以有好几个,但这个点的出度只有一个,虽然是废话,但在你判断谁存活的时候需要先判断一下,你目前队首的这个点所指向的点是否已经被杀掉,否则错炸了。
第二,也是卡住了无数英雄好汉的点,如何判断某个环是否已被用队列访问,开个bool记录看似容易,然而在哪里打标记就是大坑了,对于WA的童鞋们可以试一下这个点:
4
2 3 2 3
希望能帮到你们,在这个点中,环中每个人都死了,但如果你在将某个元素塞进队列时才将它打上标记你会发现实际已经访问了的环并未被打上标记,因此,正解是每个被塞进队列的人他所指向的人和他所指向的人所指向的人都要被打上标记。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
int n,tt[],st[],top;
bool rz[],rz2[];
int dfn[],low[],zz1;
int zz2,belong[],sum[];
void tar(int x){
zz1++;
top++;
st[top]=x;
rz[x]=rz2[x]=;
dfn[x]=low[x]=zz1;
if(!rz2[tt[x]])
{
tar(tt[x]);
low[x]=min(low[x],low[tt[x]]);
}
else if(rz[tt[x]])
{
low[x]=min(low[x],dfn[tt[x]]);
}
if(dfn[x]==low[x])
{
int v;
zz2++;
do{
v=st[top];
top--;
rz[v]=;
sum[zz2]++;
belong[v]=zz2;
}while(dfn[v]!=low[v]);
}
}
int a[],zz3,rd2[],be[];
bool fw[],js[];
int rd[],ans1,ans2;
queue<int> q1;
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&tt[i]);
rd[tt[i]]++;
}
for(int i=;i<=n;i++)
if(!rz2[i])
tar(i);
for(int i=;i<=n;i++)
{
if(rd[i]==)
{
ans1++;
q1.push(i);
fw[belong[i]]=;
}
}
while(!q1.empty())
{
int x=q1.front();
q1.pop();
fw[belong[tt[x]]]=;
if(!js[tt[x]])
{
js[tt[x]]=;
rd[tt[tt[x]]]--;
if(rd[tt[tt[x]]]==)
{
ans1++;
fw[belong[tt[tt[x]]]]=;
q1.push(tt[tt[x]]);
}
}
}
for(int i=;i<=zz2;i++)
{
if(!fw[i])
{
ans1+=sum[i]/;
}
}
for(int i=;i<=n;i++)
{
if(belong[tt[i]]!=belong[i]||tt[i]==i)
{
rd2[belong[tt[i]]]++;
}
}
for(int i=;i<=zz2;i++)
{
if(!rd2[i])
ans2++;
}
printf("%d %d",n-ans1,n-ans2);
return ;
}
对了,这道题打法不只一种,有兴趣的读者可以试一试别的方法,DP已被验证可行,贪心据说也可以,希望读者不要拘泥于一种打法。
[POI2008]枪战Maf题解的更多相关文章
- 【BZOJ1124】[POI2008]枪战Maf 贪心+思路题
[BZOJ1124][POI2008]枪战Maf Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开 ...
- BZOJ1124 [POI2008]枪战Maf[贪心(证明未完成)+拓扑排序]
吐槽:扣了几个小时,大致思路是有了,但是贪心的证明就是不会, 死磕了很长时间,不想想了,结果码代码又不会码.. 深深体会到自己码力很差,写很多行还没写对,最后别人代码全一二十行,要哭了 以下可能是个人 ...
- BZOJ 1124: [POI2008]枪战Maf
1124: [POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 617 Solved: 236[Submit][Status ...
- [POI2008]枪战Maf
[POI2008]枪战Maf 题目 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...
- bzoj 1124 [POI2008]枪战Maf 贪心
[POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 741 Solved: 295[Submit][Status][Disc ...
- bzoj1124[POI2008]枪战maf
这代码快写死我了.....死人最多随便推推结论.死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是 ...
- 【BZOJ】1124: [POI2008]枪战Maf
题意 \(n(n < 1000000)\)个人,每个人\(i\)指向一个人\(p_i\),如果轮到\(i\)了且他没死,则他会将\(p_i\)打死.求一种顺序,问死的人最少和最多的数目. 分析 ...
- BZOJ 1124: [POI2008]枪战Maf(构造 + 贪心)
题意 有 \(n\) 个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪. 因此,对于不同的开枪顺序,最后死的人也不同. 问最 ...
- 【BZOJ1124】[POI2008]枪战Maf(基环树_构造)
被教练勒令做题不能看题解后的第一道新题,自行 yy 了好久终于 AC 了(菜啊)--写博客纪念. 题目: BZOJ1124 分析: 考虑每个人向他要打的人连边.根据题意,所有点都有且只有一条出边.那么 ...
随机推荐
- Win10《芒果TV》商店版更新v3.2.0:全新播放体验,跟着爸爸,想去哪就去哪
喜迎十一月黑五大促,跟着爸爸,想去哪就去哪,<芒果TV>UWP版迅速更新v3.2.0版,全新播放页华丽蜕变,新增互动评论.猜你喜欢.宽窄屏适配.多窗体模式切换. 芒果TV UWP V3.2 ...
- 十七 bootstrap-table tableExport 导出xlsx格式表格
原文:十七 bootstrap-table tableExport 导出xlsx格式表格 在[十六.bootstrap-table javascript导出数据]中,打开导出的表格时,总会弹出一个提示 ...
- 有未经处理的异常(在 xx.exe 中): 堆栈 Cookie 检测代码检测到基于堆栈的缓冲区溢出。
一般这个问题是数组越界. 我产生这个异常的代码是这句:memcpy(tmp_cert.byKey, m_row[2], 255); 255的长度超过了char数组tmp_cert.byKey的长度.
- win32界面程序开发,自制一个会自动销毁的提示框
思路:创建线程里面启动窗口,设置定时器关闭该窗口. 创建窗口几个步骤和一般窗口无异,注册.然后createwindow,之后showwinodw,然后消息循环. 在createwindow之后,获取到 ...
- 创建dll动态链接库,并使用java调用
参考文章:http://www.cnblogs.com/matthew-2013/p/3480296.html http://blog.csdn.net/g710710/article/details ...
- 压缩大文件时如何限制CPU使用率?----几种CPU资源限制方法的测试说明
一.说明 我们的MySQL实例在备份后需要将数据打包压缩,部分低配机器在压缩时容易出现CPU打满导致报警的情况,需要在压缩文件时进行CPU资源的限制. 因此针对此问题进行了相关测试,就有了此文章. 二 ...
- C#图片灰度处理(位深度24→位深度8),用灰度数组byte[]新建一个8位灰度图像Bitmap 。
原文:C#图片灰度处理(位深度24→位深度8) #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> ...
- gcc与vs2013的三个charset编译选项
以gcc为例,它有三个命令选项:-finput-charset=gb18030-fexec-charset=utf-8-fwide-exec-charset=utf32顾名思议,input-chars ...
- 设置windows2008系统缓存大小限制,解决服务器运行久了因物理内存耗尽出僵死(提升权限后,使用SetSystemFileCacheSize API函数,并将此做成了一个Service)
声明: 找到服务器僵死的原因了,原因是虚拟内存设置小于物理内存. 只要虚拟内存设置为系统默认大小就不会出生僵死的现象了. 当时因为服务器内存48G,系统默认虚拟内存大小也是48G, 觉得太占硬盘空间, ...
- Dependency Injection 筆記 (2)
续上集,接着要说明如何运用 DI 来让刚才的范例程序具备执行时期切换实现类型的能力. (本文摘自電子書<.NET 依賴注入>) 入门范例—DI 版本 为了让 AuthenticationS ...