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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

XJOJ - 选信封(离散化+增广路)

發布時間:2024/4/11 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 XJOJ - 选信封(离散化+增广路) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:Dumbulidone和Euphemia玩一個挑卡片游戲.
Dumbulidone會給出N對信封,每個信封里有兩張不同顏色的卡片,她會讓Euphemia從中挑選任意個信封,但是一對信封中最多只能挑選一個,(信封是透明的,可以看到里面卡片顏色)。等Euphemia挑好后,Dumbulidone會嘗試從Euphemia挑出的信封中再選出若干個(不可以不取),把其中的卡片取出,若存在一種方案使得取出的卡片中,每種顏色的卡片都有偶數張,那么Dumbulidone就贏了。Euphemia想知道在自己贏的前提下,她最多能選出多少信封。

輸入格式:

第一行一個整數N。
接下來N行,每行4個整數,描述一對信封中卡片顏色,前兩個是一個信封中的,后兩個是一個信封中的。

?

輸出格式:

一個整數,表示答案。

?

樣例輸入:

樣例輸入一 4 0 1 0 5 5 1 0 5 1 2 0 1 1 5 2 0 樣例輸入二 6 1 4 1 4 2 4 2 4 0 3 0 3 0 4 0 4 4 3 4 3 1 3 1 3

?

樣例輸出:

樣例輸出一 3 樣例輸出二 4

?

數據范圍:

對于30%的數據滿足N<=10
對于100%的數據滿足N<=300,所有數<=10^7.

?

時間限制:

1S

?

空間限制:

256M

題目分析:感覺挺好的一道題目,斷斷續續想了三天差不多想明白了該怎么做,首先題目的意思比較抽象,我們需要轉換一下,可以將顏色視為點,信封視為邊,問題就轉換為了,最多可以選擇多少條邊,使得組成的圖中不存在環,因為前面的選擇會影響到全局的結果,所以不能用dp轉移狀態,在圖論中可以尋找增廣路來使得答案最優,每次不斷嘗試尋找增廣路更新答案就好了,因為數據比較小,我們可以直接枚舉每條邊,嘗試加入到圖中,如果可以直接加入的話,也就是加入某條邊后圖中仍然無環,那么這條邊就可以直接加入,相反如果加入后會出現環,那么需要尋找增廣路,這里尋找增廣路的方法和匈牙利算法的很像,也是類似于二分圖,這里二分圖的一個部分代表著已經用過的邊,另一部分代表著沒有用過的邊,如果加入某條邊后會讓圖中出現環,那么顯然這條邊和環上的其他邊是不能同時存在于一個部分的,我們可以建邊,這里的建邊是對于信封建邊,也就是代表著這兩個信封不能同時選擇,對信封建好邊后,嘗試能否增廣就好了,可以增廣的條件是找到一條信封連成的路,使得第一個信封和最后一個信封都屬于二分圖中沒有用過的邊

最后就是因為顏色比較多,但我們實際上用不到其絕對大小,所以離散化一下得到其相對大小,方便后續操作

代碼:

#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=610;vector<int>v; int f[N],n;struct Edge {int u,v,vis;Edge(){vis=0;} }Edge[N];void discreate()//離散化 {sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());for(int i=0;i<2*n;i++){Edge[i].u=lower_bound(v.begin(),v.end(),Edge[i].u)-v.begin();Edge[i].v=lower_bound(v.begin(),v.end(),Edge[i].v)-v.begin();} }int find(int x) {return f[x]==x?x:f[x]=find(f[x]); }bool merge(int x,int y) {int xx=find(x);int yy=find(y);if(xx!=yy){f[xx]=yy;return true;}return false; }struct Node {int to,id;Node(int to,int id):to(to),id(id){} };vector<Node>point[N<<1];//顏色連邊 vector<int>edge[N];//信封連邊 void init_point() {for(int i=0;i<v.size();i++)f[i]=i;for(int i=0;i<v.size();i++)point[i].clear(); }void build_point(int now)//建立點之間的聯系 { init_point();for(int i=0;i<now;i++)if(Edge[i].vis){int u=Edge[i].u;int v=Edge[i].v;point[u].push_back(Node(v,i));point[v].push_back(Node(u,i));merge(u,v);} }bool ok[N];//標記哪條邊可以作為增廣路的終邊 int vis[N];bool dfs(int u,int fa,int id)//找環 {if(u==fa)//有環 return true;vis[u]=id;for(int i=0;i<point[u].size();i++){int v=point[u][i].to;if(vis[v]==id)continue;if(dfs(v,fa,id))//將環上的所有信封與id信封連邊 {edge[id].push_back(point[u][i].id);edge[point[u][i].id].push_back(id);return true;}}return false; }void init_edge(int now) {for(int i=0;i<=(now^1);i++)edge[i].clear();memset(ok,false,sizeof(ok));memset(vis,-1,sizeof(vis)); }void build_edge(int now)//建立信封之間的聯系 {init_edge(now);for(int i=0;i<=now;i++)edge[i].push_back(i^1);for(int i=0;i<=now;i++){if(!Edge[i].vis)//如果這條邊沒被用過{if(dfs(Edge[i].u,Edge[i].v,i))//加入后有環ok[i]=false;else//無環 ok[i]=true; }} }bool dfs(int u) {vis[u]=true;for(int i=0;i<edge[u].size();i++){int v=edge[u][i];if(vis[v])continue;if((Edge[u].vis^Edge[v].vis)==1){if(ok[v]||dfs(v)){Edge[v].vis^=1;return true;}}}return false; }int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false);scanf("%d",&n);for(int i=0;i<2*n;i++){scanf("%d%d",&Edge[i].u,&Edge[i].v);v.push_back(Edge[i].u);v.push_back(Edge[i].v);}discreate();int ans=0;for(int i=0;i<2*n;i++)//遍歷每個信封 {build_point(i);//對于顏色建邊if(merge(Edge[i].u,Edge[i].v))//加入后無環,則直接加入 {Edge[i].vis=true;ans++;continue;}build_edge(i);//對于信封建邊memset(vis,false,sizeof(vis));if(dfs(i))//可以找到增廣路,則說明可以加入這條邊 {Edge[i].vis=true;ans++;}}printf("%d\n",ans);return 0; }

?

總結

以上是生活随笔為你收集整理的XJOJ - 选信封(离散化+增广路)的全部內容,希望文章能夠幫你解決所遇到的問題。

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