【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 ...
随机推荐
- MYSQL binlog 日志内容查看
记录mysql数据库真正执行更改的所有操作(DML语句),不包含那些没有修改任何数据的语句,不会记录select和show这样的语句. 二进制日志的作用: 1. 可以完成主从复制的功能 2. 进行恢复 ...
- SSIS故障排除
1.2015.09.10 SSIS部署到SQL Server上 JOB任务无法执行 说是sa账户没有执行权限 解决办法:1)SQL Server 启动时使用windows管理员账户登录.2)部署的数据 ...
- 我网站用session做的登录,为什么清除浏览器数据后还是得重新登录?session是存在服务器上的。
答案一: 你清除了浏览器数据,相当于把cookie也清了,那么你的sessionId也就没有了,所以你再次请求的时候服务器无法根据你携带的sessionid来获取对应的session,所以说需要重新登 ...
- 51nod 1402 最大值 3级算法题 排序后修改限制点 时间复杂度O(m^2)
代码: 题意,第一个数为0,相邻的数相差0或者1,有一些点有限制,不大于给定值,求这组数中可能的最大的那个数. 这题我们看一个例子:第5个数的限制为2 1 2 3 4 5 6 7 8 9 0 1 2 ...
- ASP.NET 让ajax请求webform后台方法
$.ajax({ type: "POST", url: ".aspx/getSubjectDirection", data: JSON.stringify({ ...
- Good Bye 2014 B. New Year Permutation 【传递闭包 贪心】
解题思路:给出一列数an,再给出一个矩阵d[i][j],在满足d[i][j]=1的情况下,称a[i]和a[j]可以交换,问经过交换最后得到字典序最小的数列a[n] 首先是贪心的思想,大的能换就换到后面 ...
- QT+OpenCV进行图像采集最小时延能够达到20ms
得到“算法高性能”项目的支持,目前成功地在Win10上运行WB2,感觉目前的代码速度慢.响应慢.CPU占用比例高.这种情况下3399上能够运行,说明这个平台已经是很强的了.下一步,首先在Windows ...
- 带参数,头信息,代理,cookie爬取
1.get传参 (1)汉字报错 :解释器器ascii没有汉字 url汉字转码 urllib.parse.quote safe="string.printtable" (2)字典传参 ...
- jQuery第一课 加载页面弹出一个对话框
<script type="text/javascript"> $(document).ready(function(){ alert("欢迎收看:" ...
- java几种远程服务调用协议的比较
原文地址:http://www.cnblogs.com/jifeng/archive/2011/07/20/2111183.html 一.综述 本文比较了RMI,Hessian,Burlap,Http ...