WC2016 挑战NPC
NPC,即Non_Player Character,作为游戏很重要的一种存在……
哎不对,扯远了。
这题出题人卖萌,明显不是NPC问题。
我们可以发现(通过前几个点找一找规律什么的)这题可以建立一个一般图最大匹配模型。
首先将所有的筐子拆成3个点,任选其中两点连边,然后对于每一个条件,将对应球与筐子的三个点分别连边。
可以证明(不会),最大匹配中所有球一定是匹配了的。
于是就可以用带花树(没学过)求解一般图最大匹配了。
复杂度O(VE),和二分图最大匹配一样
代码写挫了,跑了78MS。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=600+5;
struct Edge{int to,next;}e[N*N];
int head[N],cnt;
void ins(int u,int v){e[++cnt]=(Edge){v,head[u]};head[u]=cnt;
}
void insert(int u,int v){ins(u,v);ins(v,u);
}
int pa[N];
int find(int x){return pa[x]==x?x:pa[x]=find(pa[x]);
}
void merge(int u,int v){u=find(u);v=find(v);if(u!=v)pa[u]=v;
}
int n,linked[N],next[N],que[N],front,rear,mark[N],vis[N];
int lca(int u,int v){static int T=0;T++;while(true){while(u!=-1){u=find(u);if(vis[u]==T)return u;vis[u]=T;if(linked[u]!=-1)u=next[linked[u]];else u=-1;}swap(u,v);}
}
void blossom(int a,int t){while(a!=t){int b=linked[a],c=next[b];if(find(c)!=t)next[c]=b;if(mark[b]==2)mark[que[++rear]=b]=1;if(mark[c]==2)mark[que[++rear]=c]=1;merge(a,b);merge(b,c);a=c;}
}
void aug(int s){for(int i=1;i<=n;i++)next[i]=vis[i]=-1,mark[i]=0,pa[i]=i;mark[s]=1;que[rear=0]=s;for(front=0;linked[s]==-1&&front<=rear;front++){int u=que[front];for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(linked[u]==v||find(u)==find(v)||mark[v]==2)continue;if(mark[v]==1){int w=lca(u,v);if(find(u)!=w)next[u]=v;if(find(v)!=w)next[v]=u;blossom(u,w);blossom(v,w);}else if(linked[v]==-1){next[v]=u;for(u=v;u!=-1;){v=next[u];int tmp=linked[v];linked[u]=v;linked[v]=u;u=tmp;}break;}else{next[v]=u;mark[que[++rear]=linked[v]]=1;mark[v]=2;}}}
}
int sz,node[105][3],belong[N];
int main(){int cas;scanf("%d",&cas);while(cas--){int a,b,c;scanf("%d%d%d",&a,&b,&c);memset(head,0,sizeof(head));cnt=0;sz=a;for(int i=1;i<=b;i++){node[i][0]=++sz;belong[sz]=i;node[i][1]=++sz;belong[sz]=i;node[i][2]=++sz;belong[sz]=i;insert(node[i][0],node[i][1]);}n=sz;for(int i=1;i<=c;i++){int u,v;scanf("%d%d",&u,&v);for(int j=0;j<3;j++)insert(u,node[v][j]);}memset(linked,-1,sizeof(linked));for(int i=1;i<=n;i++)if(linked[i]==-1)aug(i);int ans=0;for(int i=1;i<=n;i++)if(linked[i]!=-1)ans++;printf("%d\n",ans/2-a);for(int i=1;i<=a;i++)printf("%d ",belong[linked[i]]);putchar('\n');}return 0;
}
才过了一个月发现带花树这东西感觉跟没学过一样啊TAT,蒟蒻表示有点方。
然而这题总不能就这么不会了吧,于是从论文里学了一种特殊的玩泥巴技巧
大概就是随机化+匈牙利,最好战绩水到了80分QAQ,果然数据是特殊构造的。。。。
有两个点T了,感觉时间宽一点大概就A了吧。
顺便说这个代码A掉了模板题库里的一般图最大匹配,这时候应该有老司机来hack我。。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
using namespace std;
const int N=600+5;
bool g[N][N];
bool vis[N];
int linked[N],p[N],q[N],n,anslink[N],ans;
int ba,bl;
void ins(int u,int v){g[u][v]=g[v][u]=1;
}
bool match(int u){vis[u]=1;for(int i=1;i<=n;i++){int v=q[i];if(vis[v]||!g[u][v])continue;vis[v]=1;if(!linked[v]||match(linked[v])){linked[v]=u;linked[u]=v;return true;}}return false;
}
void update(int tmp){ans=tmp;for(int i=1;i<=ba;i++)anslink[i]=linked[i];
}
void work(){memset(linked,0,sizeof(linked));int tmp=0;for(int i=1;i<=n;i++)if(!linked[p[i]])for(int t=1;t<=10;t++){memset(vis,0,sizeof(vis));if(match(p[i])){tmp++;break;}else{for(int j=1;j<=n;j++){int k=j+rand()%(n-j+1);swap(q[j],q[k]);}}}if(tmp>ans)update(tmp);
}
int b1(int i){return ba+i;
}
int b2(int i){return ba+bl+i;
}
int b3(int i){return ba+bl+bl+i;
}
int calc(int x){if(x<=ba+bl)return x-ba;if(x<=ba+bl+bl)return x-ba-bl;return x-ba-bl-bl;
}
int main(){//freopen("a.in","r",stdin);int T;scanf("%d",&T);srand(541213);while(T--){int e;scanf("%d%d%d",&ba,&bl,&e);memset(g,0,sizeof(g));for(int i=1;i<=bl;i++)ins(b1(i),b2(i));n=ba+bl*3;int a,b;while(e--){scanf("%d%d",&a,&b);ins(a,b1(b));ins(a,b2(b));ins(a,b3(b));}ans=0;for(int i=1;i<=n;i++)p[i]=q[i]=i;for(int k=1;k<=10;k++){for(int i=1;i<=ba;i++){int j=i+rand()%(ba-i+1);swap(p[i],p[j]);}for(int i=1;i<=n;i++){int j=i+rand()%(n-i+1);swap(q[i],q[j]);}work();}printf("%d\n",ans-ba);for(int i=1;i<=ba;i++)printf("%d ",calc(anslink[i]));putchar('\n');}return 0;
}
WC2016 挑战NPC相关推荐
- luogu P4258 [WC2016]挑战NPC(一般图的最大匹配,带花树,建图、拆点技巧)
整理的算法模板合集: ACM模板 luogu P4258 [WC2016]挑战NPC 如果是一堆球一堆筐,每一个筐里只能放一个球,求最大能放多少个球, 那么就是一个二分图的最大匹配问题,非常简单,我们 ...
- 【BZOJ4405】【WC2016】挑战NPC(带花树)
[BZOJ4405][WC2016]挑战NPC(带花树) 题面 BZOJ 洛谷 Uoj Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个 ...
- 【WC2016】挑战NPC 【带花树】【建图】
传送门 题意:有nnn个球和mmm个筐,每个筐最多放333个球,每个球只能放入特定的一些筐中,在题中给出.构造一种放球的方案使得nnn个球都被放在某个筐中且 球的个数不超过111 的筐的数量尽量大. ...
- 挑战NPC(洛谷-P4258)
题目描述 小 N 最近在研究 NP 完全问题,小 O 看小 N 研究得热火朝天,便给他出了一道这样的题目: 有 n 个球,用整数 1 到 n 编号.还有 m 个筐子,用整数 1 到 m 编号.每个筐子 ...
- P4258-[WC2016]挑战NPC【带花树】
正题 题目链接:https://www.luogu.com.cn/problem/P4258 题目大意 给出nnn个球,mmm个篮筐,每个球都可以被放入一些特定的篮筐,每个球都要放,要求球的个数小于等 ...
- Noip前的大抱佛脚----赛前任务
赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...
- 牛客2021年七夕节比赛 F 清楚姐姐的翅膀们【带花树】
传送门 清 楚 姐 姐 的 后 宫 有 很 多 妹 子 , 她 们 都 是 清 楚 姐 姐 的 翅 膀 . 当时觉得是匹配,就狂交了六十多发随机 题意: N N N个妹子, M M M个蝴蝶结 每个蝴 ...
- 图论 —— 带花树算法
[概述] 带花树算法用于解决一般图的最大匹配问题. 对于一个图 G(V,E),他的匹配 M 是二元组 (u,v) 组成的集合,其中 u,v∈V,(u,b)∈E,且 M 中不存在重复的点,当 |M| 最 ...
- WC酱油记——博客一个月没更新留念
不知不觉一月就这么过去了,估计二月也会很快的谜之消失吧.. 博客一直也没有更新,CF的题也是坑着一坨,考试考的我身败名裂然后还要去参加WC被虐... 总之一下就回忆一下我的WC日常吧..但是因为我是隔 ...
最新文章
- 尺取法——POJ3061
- C# 填充pdf 模板生成报告
- 删除所有的.svn文件夹
- 在reader中勾选pdf复选框_绝对可勾选的在WORD 2003中加入复选框的方法
- IMOAutocompletionViewController
- python三级联动菜单_详解element-ui级联菜单(城市三级联动菜单)和回显问题
- JAVA模拟HTTP post请求上传图片
- c语言中如何将select出来的字段值赋给一个变量,sql server 重命名列(字段)
- How to Visualize Your Recurrent Neural Network with Attention in Keras
- (MoMoCMS教程11)页面的SEO优化与外链
- 链接器工具错误 LNK2019 必须在友元声明中显式指定模板参数
- Python实现PLA(感知机)
- 全国计算机二级c语言答案,全国计算机二级C语言试题及答案
- Java时间与日期类(Calendar类的方法应用与打印日历)
- c语言图书管理系统用什么软件,编写c语言的软件 纯C语言编写图书管理系统.doc...
- qt、adb、小米屏幕滑动demo
- python爬取网易云音乐飙升榜音乐_python爬取网易云音乐热歌榜实例代码
- NOI 2005 题解
- 智能交通行业车车通信和车路通信成为ITS下一个技术亮点
- 欧卡2在线服务器返回数据错误,omsi2开启时报错是怎么回事
热门文章
- 【SQL Server】已更新或删除的行值要么不能使该行成为唯一行,要么改变了多个行 问题解决
- Auto CAD中“旋转”命令怎么使用?
- bugly android 错误不上报,Bugly不上上报日志的解决办法
- ppt怎么把图片做成翻书效果_ppt怎么做出翻页效果图文教程
- 分布式缓存(Redis)连杀
- 任买分期搞了个“斩男春计划” 我从中看到了消费分期成功的秘诀
- Xcode怎么退回旧版本?
- HTML标签之常见格式标签(1)
- 创新朋友圈植入广告,享受精准的朋友圈营销
- Ngnix+Tomcat配置负载均衡