【WC2016】挑战NPC 【带花树】【建图】
生活随笔
收集整理的這篇文章主要介紹了
【WC2016】挑战NPC 【带花树】【建图】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
題意:有nnn個球和mmm個筐,每個筐最多放333個球,每個球只能放入特定的一些筐中,在題中給出。構造一種放球的方案使得nnn個球都被放在某個筐中且 球的個數不超過111 的筐的數量盡量大。
m≤100,n≤3mm\leq 100,n\leq 3mm≤100,n≤3m
把每個筐拆成 333 個點,并每個筐的三個點兩兩之間連邊。
每個球和可以放的筐的三個點都連上邊。
然后跑一般圖最大匹配。
這樣如果一個筐的333個點被匹配的點不超過111,可以找兩個點自己匹配。
而每個球都可以且必須找一個匹配,所以最終答案是最大匹配?n最大匹配-n最大匹配?n
一個很坑的地方,最大匹配的時候球不一定都有匹配,輸出方案時會出鍋。解決方法是先從球開始增廣,這樣每個球先找到匹配點,這樣最后一定有匹配。
#include <iostream> #include <cstring> #include <cstdio> #include <cctype> #include <queue> #include <cassert> #define MAXN 1005 #define MAXM 1000005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } struct edge{int u,v;}e[MAXM]; int head[MAXN],nxt[MAXM],cnt; void addnode(int u,int v) {e[++cnt]=(edge){u,v};nxt[cnt]=head[u];head[u]=cnt; } inline void insert(int u,int v){addnode(u,v),addnode(v,u);} int mat[MAXN],pre[MAXN],col[MAXN],fa[MAXN],N; int idx[MAXN],tot; int find(const int& x){return fa[x]==x? x:fa[x]=find(fa[x]);} queue<int> q; inline int lca(int x,int y) {for (++tot;;swap(x,y))if (x){x=find(x);if (idx[x]==tot) return x;idx[x]=tot,x=pre[mat[x]];} } inline void shrink(int x,int y,int l) {while (find(x)!=l){pre[x]=y,y=mat[x];if (col[y]==2) col[y]=1,q.push(y);if (x==find(x)) fa[x]=l;if (y==find(y)) fa[y]=l;x=pre[y];} } inline int bfs(int s) {for (int i=1;i<=N;i++) pre[i]=col[i]=0,fa[i]=i;col[s]=1;while (!q.empty()) q.pop();q.push(s);while (!q.empty()){int u=q.front();q.pop();for (int i=head[u];i;i=nxt[i]){int v=e[i].v;if (find(u)==find(v)||col[v]==2) continue;if (!col[v]){col[v]=2,pre[v]=u;if (!mat[v]){for (int las;v;v=las)las=mat[pre[v]],mat[v]=pre[v],mat[pre[v]]=v;return 1;}col[mat[v]]=1,q.push(mat[v]);}else{int l=lca(u,v);shrink(u,v,l),shrink(v,u,l);}}}return 0; } int main() {for (int T=read();T;T--){memset(head,0,sizeof(head));memset(nxt,0,sizeof(nxt));cnt=0;memset(mat,0,sizeof(mat));tot=0;memset(idx,0,sizeof(idx));int n,m,e;n=read(),m=read(),e=read();N=3*m+n;for (int i=1;i<=m;i++) insert(i,i+m),insert(i,i+2*m),insert(i+m,i+2*m);for (int i=1;i<=e;i++){int v,u;v=read(),u=read();insert(3*m+v,u);insert(3*m+v,u+m);insert(3*m+v,u+2*m);}int ans=0;for (int i=N;i>=1;i--)if (!mat[i])ans+=bfs(i);printf("%d\n",ans-n);for (int i=3*m+1;i<=N;i++) printf("%d%c",(mat[i]-1)%m+1," \n"[i==N]);}return 0; }總結
以上是生活随笔為你收集整理的【WC2016】挑战NPC 【带花树】【建图】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 车祸撞到头,嗅觉丧失怎么回事?
- 下一篇: ETT学习笔记