【agc004f】Namori Grundy
那个问一下有人可以解释以下这个做法嘛,看不太懂QwQ~
Description
有一个n个点n条边的有向图,点的编号为从1到n。
给出一个数组p,表明有(p1,1),(p2,2),…,(pn,n)这n条单向边,这n条边必定构成弱连通图。
每个点均有一个权值ai,满足以下性质:
(1)所有ai均为非负整数;
(2)对于任意边(i,j),有ai≠aj;
(3)对于任意i,x(0≤x<ai),均有(i,j)满足aj=ai。
判断这样的图是否存在。(“POSSIBLE”/“IMPOSSIBLE”)
Solution
(早上花了三个小时还打挫了,心态爆炸)
弱连通图:若该有向图所有边为双向边时,满足该图为连通图,则该有向图为弱连通图。
我们容易发现,当一个点的出度为0时,它的权值也为0。我们可以对每一条边建反向边,然后进行拓扑排序,每次对新图中入度为0的点求出权值,然后删去。
若最后有剩余的点,由于原图中每个点的入度均为1,则这些点形成一个环,取其中任意一个点开始遍历即可。特别地,若原图n个点构成环,则偶环存在而奇环不存在。
下面讲一下如何求出每个点的权值:
拓扑排序:
若该点在原图中为叶子节点,则权值为0;
若不为叶子节点,则权值为原图子节点权值中未出现的数的最小值。
环:
记录原图中该点不在环上的子节点权值中未出现的数的最小值a与次小值b。若该点权值为a,则下一点无限制;若该点权值为b,则下一点权值必为a。在跑环的时候,注意判断相邻两点权值不相等以及子节点权值满足条件(2)(3)即可。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
#define next _next
struct edge{
int to,next;
}e[],g[];
int n,ehead[],ghead[];
int m=,a[]={},out[]={};
int val[];
bool vis[]={false};
queue<int>q;
stack<int>s[];
bool dfs(int u,int w,int cannot){
for(int i=ehead[u];~i;i=e[i].next)
if(vis[e[i].to])
s[val[e[i].to]].push(u);
int v=-;
for(int i=ehead[u];~i;i=e[i].next)
if(!vis[e[i].to]){
v=e[i].to;
break;
}
if(v==-){
if(w==-){
for(int i=;;i++)
if(s[i].top()!=u){
val[u]=i;
break;
}
}
else{
val[u]=w;
for(int i=;i<w;i++)
if(s[i].top()!=u){
for(int i=ehead[u];~i;i=e[i].next)
if(vis[e[i].to])
s[val[e[i].to]].pop();
return false;
}
}
bool ret=(val[u]!=cannot&&s[val[u]].top()!=u);
for(int i=ehead[u];~i;i=e[i].next)
if(vis[e[i].to])
s[val[e[i].to]].pop();
return ret;
}
if(w==-){
int flag=-;
bool ret=false;
for(int i=;;i++)
if(s[i].top()!=u){
vis[u]=true;
if(i!=cannot)
ret|=dfs(v,flag,val[u]=i);
vis[u]=false;
if(flag>-)
break;
flag=i;
}
for(int i=ehead[u];~i;i=e[i].next)
if(vis[e[i].to])
s[val[e[i].to]].pop();
return ret;
}
int flag=-;
for(int i=;i<w;i++)
if(s[i].top()!=u){
if(flag>-){
for(int i=ehead[u];~i;i=e[i].next)
if(vis[e[i].to])
s[val[e[i].to]].pop();
return false;
}
flag=i;
}
bool ret=(w!=cannot&&s[w].top()!=u&&dfs(v,flag,val[u]=w));
for(int i=ehead[u];~i;i=e[i].next)
if(vis[e[i].to])
s[val[e[i].to]].pop();
return ret;
}
int main(){
memset(ehead,-,sizeof(ehead));
memset(ghead,-,sizeof(ghead));
memset(val,-,sizeof(val));
while(!q.empty())q.pop();
scanf("%d",&n);
for(int i=;i<=n;i++){
while(!s[i].empty())
s[i].pop();
s[i].push(0x3f3f3f3f);
}
for(int i=,x;i<=n;i++){
scanf("%d",&x);
e[i]=(edge){i,ehead[x]};
g[i]=(edge){x,ghead[i]};
ehead[x]=ghead[i]=i;
a[x]++;out[x]++;
}
for(int i=;i<=n;i++)
if(out[i]==){
vis[i]=true;
q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();m++;
for(int i=ehead[u];~i;i=e[i].next)
s[val[e[i].to]].push(u);
for(int i=;;i++)
if(s[i].top()!=u){
val[u]=i;
break;
}
for(int i=ehead[u];~i;i=e[i].next)
s[val[e[i].to]].pop();
for(int i=ghead[u];~i;i=g[i].next)
out[g[i].to]--;
for(int i=ghead[u];~i;i=g[i].next)
if(out[g[i].to]==){
vis[g[i].to]=true;
q.push(g[i].to);
}
}
if(m==n){
puts("POSSIBLE");
return ;
}
if(m==){
puts(n&?"IMPOSSIBLE":"POSSIBLE");
return ;
}
for(int i=;i<=n;i++)
if(!vis[i]){
puts(dfs(i,-,-)?"POSSIBLE":"IMPOSSIBLE");
return ;
}
return ;
}
(话说环套树的题是真的烦[○・`Д´・ ○])
【agc004f】Namori Grundy的更多相关文章
- 【agc004F】Namori
Portal -->agc004F Solution 好神仙的转化qwq 首先我们可以先考虑\(m=n-1\)的情况下,也就是树的情况下要怎么做 我们可以将这个问题转化一下:我们对这颗 ...
- 【ARC079F】Namori Grundy
Description 题目链接 大意:给一张基环外向树.要求给每一个点确定一个值,其值为所有后继点的\(\text{mex}\).求是否存在确定权值方案. Solution 首先,对于叶子节点,其权 ...
- 【atcoder F - Namori】**
F- Namori http://agc004.contest.atcoder.jp/tasks/agc004_f Time limit : 2sec / Memory limit : 256MB S ...
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
随机推荐
- Codeforces 703D Mishka and Interesting sum 离线+树状数组
链接 Codeforces 703D Mishka and Interesting sum 题意 求区间内数字出现次数为偶数的数的异或和 思路 区间内直接异或的话得到的是出现次数为奇数的异或和,要得到 ...
- VC6之MAP文件生成及格式
文件生成方式: 在 VC 中,我们可以按下 Alt+F7 ,打开“Project Settings”选项页,选择 C/C++ 选项卡,并在最下面的 Project Options 里面输入:/Zd , ...
- [转]m3u8直播测试地址
http://www.cnblogs.com/yuandaozhe/p/5755453.html 调试m3u8的时候需要测试地址 找了几个,备用一下 安徽卫视 http://stream2.ahtv. ...
- JAR包放在WEB-INF/lib子目录报ClassNotFoundException解决方案
对于Java Web应用依赖的jar包,我们通常会放到WEB-INF/lib目录下,但是笔者喜欢把不同框架的jar包放在不同的子目录下,例如新建一个struts目录存放struts框架的jar包等. ...
- (转载)Android之有效防止按钮多次重复点击的方法(必看篇)
为了防止测试妹子或者用户频繁点击某个按钮,导致程序在短时间内进行多次数据提交or数据处理,那到时候就比较坑了~ 那么如何有效避免这种情况的发生呢? 我的想法是,判断用户点击按钮间隔时间,如果间隔时间太 ...
- swift语言点评十六-Initialization && Deinitialization
initial value:必须初始化.不影响观察者 Classes and structures must set all of their stored properties to an appr ...
- Monitor (synchronization)条件变量-安全对象
In concurrent programming, a monitor is a synchronization construct that allows threads to have both ...
- 3ds Max怎么制作亮木材质的球体
3DSMax怎么制作亮木材质的球体?3DSMax中想要设计一款亮木材质的球体,该怎么设置呢?下面我们就来看看详细的教程,需要的朋友可以参考下! 1.运行软件,选择材质编辑器图标: 3.双击拖拽出的材质 ...
- data structure alignment(数据对齐)
概述: 数据对齐指数据在计算机内存中排放和获取的方式.包含三个方面:数据对齐(data alignment).数据结构填充(data alignment).打包(packing) 如果数据是自然对齐的 ...
- window安装特定补丁(勒索病毒)
最近出现震惊的蠕虫病毒(勒索病毒),微软也做出相应的安全补丁来修复 MS17-010.这时有些同学不想打开电脑 的自动更新,这样会下载大量补丁,要更新完这些补丁要好几个小时,为了不影响正常工作,我们就 ...