那个问一下有人可以解释以下这个做法嘛,看不太懂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的更多相关文章

  1. 【agc004F】Namori

    Portal -->agc004F Solution  好神仙的转化qwq ​  首先我们可以先考虑\(m=n-1\)的情况下,也就是树的情况下要怎么做  我们可以将这个问题转化一下:我们对这颗 ...

  2. 【ARC079F】Namori Grundy

    Description 题目链接 大意:给一张基环外向树.要求给每一个点确定一个值,其值为所有后继点的\(\text{mex}\).求是否存在确定权值方案. Solution 首先,对于叶子节点,其权 ...

  3. 【atcoder F - Namori】**

    F- Namori http://agc004.contest.atcoder.jp/tasks/agc004_f Time limit : 2sec / Memory limit : 256MB S ...

  4. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

  5. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  6. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  7. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  8. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  9. Python高手之路【三】python基础之函数

    基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...

随机推荐

  1. RabbitMQ笔记(3)

    消息从产生--->结束 1.生产者--->交换机--->队列--->消费者 2.生产者--->交换机--->队列 首先: 生产者:Exchange = n:1 Ex ...

  2. HDU 1338 Game Prediction【贪心】

    解题思路: 给出 n  m 牌的号码是从1到n*m 你手里的牌的号码是1到n*m之间的任意n个数,每张牌都只有一张,问你至少赢多少次 可以转化为你最多输max次,那么至少赢n-max次 而最多输max ...

  3. RocketMQ学习笔记(7)----RocketMQ的整体架构

    1. RocketMQ主要的9个模块,如图: 2. 模块介绍 1. rocketmq-common:通用的常量枚举,基类方法或者数据结构,按描述的目标来分包,通俗易懂.报名有admin,consume ...

  4. 我的Java历程_写出这个数

    lzJava基础进行中,今天偶然间看到的一个题目: 读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字.如下代码: import java.util.*;public class Ma ...

  5. 每个IT安全专业人员应该知道的12种根本漏洞

    每个IT安全专业人员应该知道的12种根本漏洞 每年,IT安全专业人员都面临着数千个新的软件漏洞和数百万个不同的恶意软件程序,但只有12种根本漏洞会让这些软件漏洞和恶意软件程序攻击你的设备.了解这些根本 ...

  6. POJ-3660 Cow Contest Floyd传递闭包的应用

    题目链接:https://cn.vjudge.net/problem/POJ-3660 题意 有n头牛,每头牛都有一定的能力值,能力值高的牛一定可以打败能力值低的牛 现给出几头牛的能力值相对高低 问在 ...

  7. [HEOI2012]采花(树状数组+离线)

    听说这题的所发和HH的项链很像. 然而那道题我使用莫队写的... 这是一个套路,pre数组加升维(在线). 记录一个\(pre\)数组,\(pre[i]\)代表上一个和i颜色相同的下标. 我们把询问离 ...

  8. HashMap和Hashtable的区别。

    HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable ...

  9. C语言声明语句

    设计理念: C语言的一个设计理念就是声明变量和使用变量的形式应该是一致的 优点:声明变量和使用变量时的运算符优先级是相同的 缺点:运算符的优先级是C语言过度解析的部分之一 术语: 变量声明中使用到的符 ...

  10. java流与文件的操作 文件加密

    课后作业 1,源代码 import java.io.*; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttribu ...