poj2723 2sat判断解+二分
生活随笔
收集整理的這篇文章主要介紹了
poj2723 2sat判断解+二分
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
典型的2-sat問題,題意:有m個門,每個門上倆把鎖,開啟其中一把即可,現在給n對鑰匙(所有
數代表原來的一個“狀態”/“命題”/“數據”,使之01為一對(只取一個),23一對,...依次,建圖
此題要求最值,二分即可。
注意點(WA之因):1.編號后全圖全按編號走啊!原來數據基本無用,只是有時候輸出時之用,或建立
數據雙向關系!2.對于每次二分,對應數要重新建圖,注意初始化!
鑰匙編號0123456...2n-1),每對鑰匙只能用一把,要求盡可能開門多(按順序,前max個)。
關鍵是題意的分析與轉化,只能選一?必然2-sat,每給一對門上的鎖對應鑰匙的編號,說:必需要這
倆把鑰匙的一把(至少),即:a^b,所以,建圖了可以,總結通法:對應的數據編號:0123..,每個數代表原來的一個“狀態”/“命題”/“數據”,使之01為一對(只取一個),23一對,...依次,建圖
此題要求最值,二分即可。
注意點(WA之因):1.編號后全圖全按編號走啊!原來數據基本無用,只是有時候輸出時之用,或建立
數據雙向關系!2.對于每次二分,對應數要重新建圖,注意初始化!
ps:一晚沒成功,結果早上起來2分鐘,AC!上午效率就是高!切記不可熬夜!身體健康第一位!
#include<iostream> //36MS #include<cstring> #include<cstdio> #include<stack> #include<vector> using namespace std; const int MAX=3000; vector<int>keys(MAX);int n,m;int times=0; int belong[MAX]; int low[MAX];int dfn[MAX];int visited[MAX];int isinstack[MAX];stack<int>s; int scc[MAX];int numblock=0; struct request //條件 {int a,b; }; request requests[MAX]; vector<vector<int> >edges(MAX); //圖 void clear() {times=numblock=0;for(int i=0;i<2*n;i++){visited[i]=dfn[i]=low[i]=isinstack[i];scc[i]=-1;edges[i].clear();} } void tarjan(int u) //dfs {dfn[u]=low[u]=++times;isinstack[u]=1;s.push(u); int len=edges[u].size();for(int i=0;i<len;i++){int v=edges[u][i];if(visited[v]==0){visited[v]=1;tarjan(v);if(low[u]>low[v])low[u]=low[v];}else if(isinstack[v]&&dfn[v]<low[u])low[u]=dfn[v];}if(low[u]==dfn[u]){numblock++;int cur;do{cur=s.top();s.pop();isinstack[cur]=0;scc[cur]=numblock;}while(cur!=u);} } bool check(int maxnum) //檢查 {clear();for(int i=0;i<maxnum;i++) //這里的數據的轉化{if(requests[i].a==requests[i].b){edges[belong[requests[i].a]^1].push_back(belong[requests[i].b]);}else{edges[belong[requests[i].a]^1].push_back(belong[requests[i].b]);edges[belong[requests[i].b]^1].push_back(belong[requests[i].a]);}}for(int i=0;i<2*n;i++)if(visited[i]==0){visited[i]=1;tarjan(i);}for(int i=0;i<2*n;i+=2)if(scc[i]==scc[i+1]) //因為這里跪了半天!注意編號!圖頂點用的都是編號!return 0;return 1; } void readin() {for(int i=0;i<2*n;i++){scanf("%d",&keys[i]);belong[keys[i]]=i;}for(int i=0;i<m;i++){scanf("%d%d",&requests[i].a,&requests[i].b);} } int main() {while(~scanf("%d%d",&n,&m)&&(n||m)){readin();int left=0,right=m,mid;int count=-1;while(right>left) //二分之{mid=(left+right)/2;if(mid==count&&mid==left) //注意出口!{if(check(left+1))left++;break;}if(check(mid))left=mid;else right=mid;count=mid;}printf("%d\n",left);} }總結
以上是生活随笔為你收集整理的poj2723 2sat判断解+二分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 日期和时间基本概念
- 下一篇: GBK字符串转Unicode字符串