日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

挑战NPC(洛谷-P4258)

發(fā)布時(shí)間:2025/3/17 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 挑战NPC(洛谷-P4258) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目描述

小 N 最近在研究 NP 完全問(wèn)題,小 O 看小 N 研究得熱火朝天,便給他出了一道這樣的題目:

有 n 個(gè)球,用整數(shù) 1 到 n 編號(hào)。還有 m?個(gè)筐子,用整數(shù) 1?到 m?編號(hào)。每個(gè)筐子最多能裝 3 個(gè)球。

每個(gè)球只能放進(jìn)特定的筐子中。 具體有 e?個(gè)條件,第 i 個(gè)條件用兩個(gè)整數(shù) vi 和 ui?描述,表示編號(hào)為 vi?的球可以放進(jìn)編號(hào)為 ui?的筐子中。

每個(gè)球都必須放進(jìn)一個(gè)筐子中。如果一個(gè)筐子內(nèi)有不超過(guò) 1 個(gè)球,那么我們稱這樣的筐子為半空的。

求半空的筐子最多有多少個(gè),以及在最優(yōu)方案中, 每個(gè)球分別放在哪個(gè)筐子中。

小 N 看到題目后瞬間沒(méi)了思路,站在旁邊看熱鬧的小 I 嘿嘿一笑:“水題!” 然后三言兩語(yǔ)道出了一個(gè)多項(xiàng)式算法。

小 N 瞬間就驚呆了,三秒鐘后他回過(guò)神來(lái)一拍桌子:“不對(duì)!這個(gè)問(wèn)題顯然是 NP 完全問(wèn)題,你算法肯定有錯(cuò)!”

小 I 淺笑:“所以,等我領(lǐng)圖靈獎(jiǎng)吧!”

小 O 只會(huì)出題不會(huì)做題,所以找到了你——請(qǐng)你對(duì)這個(gè)問(wèn)題進(jìn)行探究,并寫一個(gè)程序解決此題。

輸入輸出格式

輸入格式:

輸入文件 npc.in 第一行包含 1 個(gè)正整數(shù) T, 表示有 T 組數(shù)據(jù)。

對(duì)于每組數(shù)據(jù),第一行包含 3?個(gè)正整數(shù) nn,m,e, 表示球的個(gè)數(shù),筐子的個(gè)數(shù)和條件的個(gè)數(shù)。

接下來(lái) e?行,每行包含 2?個(gè)整數(shù) vi,ui,表示編號(hào)為 vi?的球可以放進(jìn)編號(hào)為 ui?的筐子。

輸出格式:

輸出文件為 npc.out。

對(duì)于每組數(shù)據(jù),先輸出一行,包含一個(gè)整數(shù),表示半空的筐子最多有多少個(gè)。

然后再輸出一行,包含?n?個(gè)整數(shù)?p1?,p2?,...,pn?,相鄰整數(shù)之間用空格隔開(kāi),表示一種最優(yōu)解。其中?pi??表示編號(hào)為?i?的球放進(jìn)了編號(hào)為?pi??的筐子。 如果有多種最優(yōu)解,可以輸出其中任何一種。

輸入輸出樣例

輸入樣例#1:

1
4 3 6
1 1
2 1
2 2
3 2
3 3
4 3

輸出樣例#1:

2
1 2 3 3

說(shuō)明

對(duì)于所有數(shù)據(jù),T≤5,1≤n≤3m。 保證 1≤vi?≤n,1≤ui?≤m,且不會(huì)出現(xiàn)重復(fù)的條件。

保證至少有一種合法方案,使得每個(gè)球都放進(jìn)了筐子,且每個(gè)筐子內(nèi)球的個(gè)數(shù)不超過(guò)?3。

各測(cè)試點(diǎn)滿足以下約定:?

思路:

簡(jiǎn)單來(lái)說(shuō),就是有 n 個(gè)球,m 個(gè)筐,一個(gè)筐最多裝三個(gè)球,有 e 個(gè)條件表示哪個(gè)球能裝哪個(gè)筐里,要求每個(gè)球必須進(jìn)一個(gè)筐,問(wèn)不超過(guò)一個(gè)球的筐最多有幾個(gè)

由于一個(gè)筐最多裝三個(gè)球,因此將每個(gè)筐拆成三個(gè)點(diǎn),代表三個(gè)空位,然后對(duì)每個(gè)球可以放入的筐添加三條對(duì)應(yīng)邊,再將每個(gè)筐的三個(gè)點(diǎn)間互相連邊,跑帶花樹(shù)算法求最大匹配即可

源代碼

#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<bitset> #define EPS 1e-9 #define PI acos(-1.0) #define INF 0x3f3f3f3f #define LL long long #define Pair pair<int,int> const int MOD = 1073741824; const int N = 2000+5; const int dx[] = {-1,1,0,0,-1,-1,1,1}; const int dy[] = {0,0,-1,1,-1,1,-1,1}; using namespace std;struct Edge {int to,next; } edge[N*N*2]; int head[N],tot; int n;//n個(gè)點(diǎn) int father[N],pre[N];//father記錄一個(gè)點(diǎn)屬于哪個(gè)一個(gè)點(diǎn)為根的花 int Q[N*N*2],first,tail;//bfs隊(duì)列 int match[N];//匹配 bool odd[N],vis[N];//odd記錄一個(gè)點(diǎn)為奇點(diǎn)/偶點(diǎn),1為奇,0為偶 int timeBlock;//LCA時(shí)間戳 int top[N],rinedge[N];void addEdge(int u,int v) {//添邊edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++; } int Find(int x){//并查集尋找根節(jié)點(diǎn)if(father[x]!=x)return father[x]=Find(father[x]);return x; } int lca(int x, int y){//求解最近公共祖先timeBlock++;while(x){rinedge[x]=timeBlock;x=Find(top[x]);}x=y;while(rinedge[x]!=timeBlock)x=Find(top[x]);return x; } void blossom(int x, int y, int k) {//將奇環(huán)縮成一個(gè)點(diǎn)并將原來(lái)是奇點(diǎn)的點(diǎn)變?yōu)榕键c(diǎn)并加入隊(duì)列while(Find(x)!=Find(k)){pre[x]=y;y=match[x];odd[y]=false;Q[tail++]=y;father[Find(x)]=k;father[Find(y)]=k;x=pre[y];} } bool bfs(int s) {memset(top,0,sizeof(top));memset(pre,0,sizeof(pre));memset(odd,false,sizeof(odd));memset(vis,false,sizeof(vis));for(int i=1;i<=n;i++)father[i]=i;vis[s]=true;first=tail=0;Q[tail++]=s;while(first!=tail){int now=Q[first++];for(int i=head[now];i!=-1;i=edge[i].next){int to=edge[i].to;if(!vis[to]){top[to]=now;pre[to]=now;odd[to]=true;vis[to]=true;if(!match[to]){int j=to;while(j){int x=pre[j];int y=match[x];match[j]=x;match[x]=j;j=y;}return true;}vis[match[to]]=true;top[match[to]]=to;Q[tail++]=match[to];}else if(Find(now)!=Find(to) && odd[to]==false) {int k=lca(now,to);blossom(now,to,k);blossom(to,now,k);}}}return false; }int main() {int t;scanf("%d",&t);while(t--){memset(head,-1,sizeof(head));memset(match,0,sizeof(match));tot=0;int p,m,e;scanf("%d",&p);scanf("%d",&m);scanf("%d",&e);for(int i=1;i<=e;i++){int x,y;scanf("%d%d",&x,&y);y=p+(y-1)*3;addEdge(x,y+1); addEdge(y+1,x);addEdge(x,y+2); addEdge(y+2,x);addEdge(x,y+3); addEdge(y+3,x);}for(int i=1;i<=m;i++){int point=p+(i-1)*3;addEdge(point+1,point+2);addEdge(point+2,point+1);}n=p+m*3;//總點(diǎn)數(shù)int res=0;for(int i=1;i<=n;i++)if(!match[i])res+=bfs(i);res-=p;printf("%d\n",res);for(int i=1;i<=p;i++)printf("%d ",(match[i]-p-1)/3+1);printf("\n");}return 0; }

?

總結(jié)

以上是生活随笔為你收集整理的挑战NPC(洛谷-P4258)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。