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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分组[测试点分支+二分图判定]

發布時間:2025/5/22 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分组[测试点分支+二分图判定] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意大概是給你一個序列,讓你把這個序列劃分成幾個連續的小組,每個小組又可以分成兩份,要求使所分小組數最小,且滿足每個小組內部的每個小團體都不能有任意兩個數相加為

整數的平方......

1.首先一個很重要的點,數據范圍是1<<17,2*(1<<17)=1<<18;而sqrt(1<<18)=1<<9=512;所以枚舉判斷是否合法,即可只枚舉512次而避免了O(N^2)復雜度;

2.要求字典序最小的答案,而咱們又要貪心,所以從后往前轉移.....

3.其實依題,判斷每個小組是否合法,因為每個小組內只有且僅有2個小團體,所以,就可以是看成是二分圖判斷問題,如果判斷可以構成二分圖,就繼續往下搜;

我們先來回憶一下二分圖;

二分圖的定義是:把一組點分成兩組,且每組內部的點沒有連邊聯系,而兩組之間可以有連邊;

這樣考慮的話

我們可以把每個數與其敵對數(當然是同組內的)先建邊,這樣建成的邊像(關押罪犯)一樣可以是看成仇恨邊,而在這道題里,有仇恨的數不能放在同一個集合里,,同一集合的

數是不可有仇恨連邊的,而兩組之間可以有仇恨邊,仔細讀一下,和二分圖定義是一樣的;

好我們就可以把這個題轉化成二分圖判斷題;

而從后枚舉,就是讓你目前的二分圖盡可能長,所以就是去每次添加一個點,然后把這個點加入二分圖,看是否仍能符合二分圖的性質;

然后就到了如何去判斷二分圖;

一.交叉染色法判斷二分圖

1 bool judge=0; 2 void dfs(int x,int fa,int cols){ 3 col[x]=cols; 4 if(judge)return ; 5 for(int i=fir[x],y;i;i=edge[i].nxt){ 6 y=edge[i].to; 7 if(judge)return ; 8 if(y==fa)continue; 9 if(cols+col[y]==3)continue;//顏色編號為1和二 10 if(cols==col[y])return judge=1,void(); 11 if(!col[y])dfs(y,x,3-cols); 12 } 13 } 14 //其實就是你和與你連邊的點是敵對的,你不能和你敵對的點有相同的顏色即同一集合,又因為//和你連邊的都是對立點,所以你就把和你連邊的點染成異色,只要不是和你對立的點還和你有//相同的顏色(在同一個集合)就可以了; 交叉染色法

二.并查集牛逼法(弓主任(交線牛逼法))

1 #define MAXN 100050 2 #define mat(x) (x+N) 3 //虛點~ 4 inline int find(int x){ 5 return (x==fa[x])?x:fa[x]=find(fa[x]); 6 } 7 int fa[MAXN],N; 8 vector<int>ans; 9 int main() 10 { 11 int M=(N<<1); 12 for(int i=1;i<=M;i+=5){ 13 fa[i]=i; 14 if(i+1<=M)fa[i+1]=i+1; 15 if(i+2<=M)fa[i+2]=i+2; 16 if(i+3<=M)fa[i+3]=i+3;//卡常一下 17 if(i+4<=M)fa[i+4]=i+4; 18 }//并查集要用到拓展域和虛點 19 //虛點的作用是為了讓與和你對立的點不再和你連邊而和你的虛點連邊 20 //而你的虛點就可以設為(i+N) 21 bool judge=0; 22 for(int i=N;i>=1;--i){ 23 judge=0; 24 for(int j=0,y;j<to[i].size();++j){ 25 y=to[i][j]; 26 fa[find(i)]=fa[find(mat(y)]; 27 fa[find(y)]=fa[find(mat(i))]; 28 if(fa[i]==fa[y]){//其實也一樣,就是你把和你敵對的點連在了你的虛點上, 29 //然后你的虛點不能和你連便,因為你不能和你自己敵對 30 //用并查集維護就是可以加快你判斷與你對立的點是否和你在同一個集合里 31 //用交叉染色法判一次O(N),他判一次差不多O(1); 32 // 所以還是這個比較好 33 judge=1;break; 34 } 35 } 36 if(judge){ 37 //清零數組一大堆懶得寫了反正是思路; 38 ans.push_back(i); 39 } 40 } 41 42 } 并查集判斷二分圖

差不多這個題最重要的就是判斷二分圖;

模板好題提醒(關押罪犯)應該先做;

1 #include<bits/stdc++.h> 2 using namespace std; 3 int N,K; 4 int col[331079],fir[331079]; 5 bool v[331079]; 6 int h[331707]; 7 int c[331079]; 8 vector<int>ans; 9 int has[331079]; 10 vector<vector<int> >to(331079),num(331107); 11 struct ct{int st,ed,nxt;}lian[10011007];int tot=0; 12 13 inline int max(int a,int b){return a>b?a:b;} 14 15 inline void add(int x,int y){ 16 lian[++tot].st=x; 17 lian[tot].ed=y; 18 lian[tot].nxt=fir[x]; 19 fir[x]=tot; 20 } 21 int maxn=0; 22 bool judge=0; 23 void dfs(int x,int fa,int cs){ 24 c[x]=cs;register int y; 25 if(judge)return ; 26 for(int i=fir[x];i;i=lian[i].nxt){ 27 y=lian[i].ed; 28 if(judge)return ; 29 if(!v[y])continue; 30 if(y==fa)continue; 31 if(c[y]+cs==3)continue; 32 if(c[y]==cs)return judge=1,void(); 33 if(!c[y])dfs(y,x,3-cs); 34 } 35 } 36 37 int main() 38 { 39 scanf("%d%d",&N,&K); 40 for(int i=1;i<=N;++i){ 41 scanf("%d",&col[i]); 42 } 43 int lim=512; 44 if(K==1){ for(int i=N;i>=1;--i){ 45 for(int j=lim;j*j>=col[i];--j){ 46 if(v[j*j-col[i]]){ 47 for(int k=1;k<=has[0];++k) 48 v[has[k]]=0; 49 has[0]=0;ans.push_back(i); 50 break; 51 } 52 } 53 v[col[i]]=1;has[++has[0]]=col[i]; 54 } 55 } 56 57 else 58 { 59 register int deta=1<<17; 60 for(int i=N;i>=1;--i){ 61 judge=0; 62 lim=sqrt(maxn+col[i])+1; 63 for(int j=lim;j*j>=col[i];--j) 64 if(j*j-col[i]<=(deta)){ 65 for(int k=0;k<h[j*j-col[i]];++k){ 66 register int p=num[j*j-col[i]][k]; 67 if(p!=i){ 68 add(p,i); 69 add(i,p); 70 } 71 } 72 } 73 v[i]=1; 74 dfs(i,i,1); 75 //for(int is=0;is<=131072;++is)c[is]=0; 76 if(judge){ 77 has[++has[0]]=i; 78 ans.push_back(i);//c[i]=0; 79 for(register int j=1;j<=has[0];j+=4){ 80 v[has[j]]=0,c[has[j]]=0,fir[has[j]]=0,h[col[j]]=0,num[col[j]].clear(); 81 if(j+1<=has[0]){v[has[j+1]]=0,c[has[j+1]]=0,fir[has[j+1]]=0,h[col[j+1]]=0,num[col[j+1]].clear();} 82 if(j+2<=has[0]){v[has[j+2]]=0,c[has[j+2]]=0,fir[has[j+2]]=0,h[col[j+2]]=0,num[col[j+2]].clear();} 83 if(j+3<=has[0]){v[has[j+3]]=0,c[has[j+3]]=0,fir[has[j+3]]=0,h[col[j+3]]=0,num[col[j+3]].clear();} 84 } 85 tot=0; 86 has[0]=0; 87 maxn=col[i]; 88 } 89 v[i]=1; 90 has[++has[0]]=i; 91 h[col[i]]++; 92 maxn=max(maxn,col[i]); 93 num[col[i]].push_back(i); 94 for(register int j=1;j<=has[0];j+=5){ 95 c[has[j]]=0; 96 if(j+1<=has[0])c[has[j+1]]=0; 97 if(j+2<=has[0])c[has[j+2]]=0; 98 if(j+3<=has[0])c[has[j+3]]=0; 99 if(j+4<=has[0])c[has[j+4]]=0; 100 } 101 } 102 } 103 printf("%d\n",(ans.size())+1); 104 for(int i=ans.size()-1;i>=0;--i){ 105 printf("%d ",ans[i]); 106 } 107 printf("\n"); 108 } 因卡常恰巧AC的代碼

?

轉載于:https://www.cnblogs.com/wang-hesong/p/11298298.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的分组[测试点分支+二分图判定]的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。