java請求介面接收樹形結構資料丟失問題
阿新 • • 發佈:2021-10-15
傳送門
解題思路
思想:將問題轉化為圖論問題。
因為一個點只有兩個狀態,所以每個點可以拆成 i 和 i+n 兩個點,u 連向 v 表示選擇 u 就必須選擇 v。
根據條件建圖(注意一定要建對應的反向邊(例如建立 u->v+n,就必須再連 v->u+n))後,跑一遍Tarjan求強連通分量。若發現存在一個 i 和 i+n 在同一個SCC裡,則無解。
否則就比較i和i+n所在scc的編號大小,一定是選擇編號小的更優(scc編號小相當於拓撲序編號大)。
AC程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<map> #include<bitset> #include<stack> using namespace std; template<class T>inline void read(T &x) { x=0;register char c=getchar();register bool f=0; while(!isdigit(c))f^=c=='-',c=getchar(); while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar(); if(f)x=-x; } template<class T>inline void print(T x) { if(x<0)putchar('-'),x=-x; if(x>9)print(x/10); putchar('0'+x%10); } const int maxn=2e6+5; int n,m,dfn[maxn],p[maxn],low[maxn],times,scc_cnt,in[maxn],cnt; struct node{ int v,next; }e[maxn]; stack<int> s; void insert(int u,int v){ cnt++; e[cnt].v=v; e[cnt].next=p[u]; p[u]=cnt; } void dfs(int u){ dfn[u]=low[u]=++times; s.push(u); for(int i=p[u];i!=-1;i=e[i].next){ int v=e[i].v; if(dfn[v]==0){ dfs(v); low[u]=min(low[u],low[v]); } else{ if(!in[v]) low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]){ scc_cnt++; while(!s.empty()){ int x=s.top();s.pop(); in[x]=scc_cnt; if(x==u) break; } } } int main(){ ios::sync_with_stdio(false); memset(p,-1,sizeof(p)); read(n);read(m); for(int i=1;i<=m;i++){ int x,a,y,b; read(x);read(a);read(y);read(b); if(a==1&&b==1){ insert(x+n,y); insert(y+n,x); } if(a==1&&b==0){ insert(x+n,y+n); insert(y,x); } if(a==0&&b==1){ insert(x,y); insert(y+n,x+n); } if(a==0&&b==0){ insert(x,y+n); insert(y,x+n); } } for(int i=1;i<=2*n;i++) if(!in[i]) dfs(i); for(int i=1;i<=n;i++){ if(in[i]&&in[i+n]&&(in[i]==in[i+n])){ puts("IMPOSSIBLE"); return 0; } } puts("POSSIBLE"); for(int i=1;i<=n;i++){ print(in[i]>in[i+n]?0:1); putchar(' '); } return 0; }