1. 程式人生 > >【圖論】2018國慶三校聯考D5T2

【圖論】2018國慶三校聯考D5T2

在這裡插入圖片描述

分析:

題意非常醜陋。。。簡化出來就一句話:每個點有選中、未選中兩種狀態,現在給出一些矛盾關係,要求加入儘可能少的矛盾關係,使得沒有合法方案。

如此2sat的模型,顯然需要2sat的連邊方式。。。然後直接列舉每個位置選、不選是否合法即可。若不選合法,則考慮其練的邊是否有一個選擇的點,如果有則可以用1的代價使得這個點不選非法。具體的情況見程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf #define PF printf #define MAXN 4010 using namespace std; struct node{ int x; node *nxt; }edge[MAXN*4]; node *head[MAXN],*ncnt=edge; int n,m; void add_edge(int u,int v){ ncnt++; ncnt->x=v; ncnt->nxt=head[u]; head[u]=ncnt; } bool vis[MAXN]; void dfs(int x){ vis[x]=1; for
(node *v=head[x];v!=NULL;v=v->nxt){ int u=v->x; if(vis[u]==0) dfs(u); } } int query(int x){ memset(vis,0,sizeof vis); dfs(x); for(int i=1;i<=n;i++) if(vis[i]==1&&vis[i+n]==1) return 0; return 1; } int check(){ for(int i=1;i<=n;i++) if(vis[i]==1) return 1; return
0; } int l[MAXN]; int main(){ freopen("god.in","r",stdin); freopen("god.out","w",stdout); int t; SF("%d",&t); while(t--){ SF("%d%d",&n,&m); for(int i=1;i<=n*2;i++) head[i]=NULL; ncnt=edge; int ans=3,u,v; for(int i=1;i<=m;i++){ SF("%d%d",&u,&v); if(u<0) u=-u+n; if(v<0) v=-v+n; add_edge(u,(v+n)%(2*n)); add_edge(v,(u+n)%(2*n)); } for(int i=1;i<=n;i++){ int res1=query(i); int res2=query(i+n); int con=check(); if(res2==0) ans=min(ans,res1); else if(con==1) ans=min(ans,1+res1); } if(ans==3) PF("No Way\n"); else PF("%d\n",ans); } }