題解【[FJOI2018]所羅門王的寶藏】
阿新 • • 發佈:2019-02-16
con define 思路 line 改進 turn .so 增加 stdin
本題解同步於luogu
emmm切了近年省選題來寫題解啦qwq
該題較其他省選題較水吧(否則我再怎麽做的出來
思路是圖論做法,做法上樓上大佬已經講的很清楚了,我來談談代碼實現上的一些細節
\[\text{設節點1...2n,i}\in\text{1-n表示i行,i}\in\text{(n+1)-2n時表示i-n列}\]
\[\text{當我們讀到一顆綠寶石(x,y,k)時,就從x向y+n連一條權值為k的邊}\]
\[\text{當我們連完邊後會發現給一行/一列增加a就相當於把與這個點相連的所有邊權值增加a}\]
\[\text{這個加邊權可以轉化為加點權}\]
\[\text{設}onk_i\text{表示在這個節點上的點擊次數,}\]
\[\text{搜索起始節點的初值為與這個節點所連邊中權值最小的}\]
\[\text{那麽已知兩點i,j以及}edge_{i,j}\text{和}onk_i\text{,那麽由題目條件易得}onk_j=edge_{i,j}-onk_i\]
\[\text{那麽直接dfs}\]
時間復雜度為\[O(T\times(KlogK+K)) = O(TNlogN)\]要改進也行,因為我們對於每個點只要最大數所以沒必要sort,但當我想到這一點時已經AC本題~
\[Talk\;is\;free\;,\;show\;me\;the\;code\]
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> #include<cstring> #define MAXN 1005 using namespace std ; inline void read(int &x) { scanf("%d",&x) ; } class getsol { public: //========data======== vector<pair<int,int> > edge[MAXN*2] ; //pair第一維是邊權,第二維是到達邊的編號 int n , m , k , onk[MAXN*2] , inq[MAXN*2] , flag ;//inq表示是否被搜到 //========func======== void add(int x,int y,int v) { edge[x].push_back(make_pair(v,y)) ; //加邊 } bool check(int u,int v,int w) { //check , 判斷v點是否可行 if(onk[u]+onk[v]!=w) return 0 ; return 1 ; } void dfs(int D) { //cout<<"DFS : START SEARCH IN DOT "<<D<<endl ; if(flag==0) return ; inq[D] = 1 ; for(auto& i : edge[D]) { //對於每個edge[D]中的元素i ///cout<<"DFS : SEARCH IN DOT "<<i.second<<endl ; if(flag==0) return ; //cout<<"In dot : "<<i.second<<endl ; int ver = i.second , edgeval = i.first ; if(inq[ver]) { if(flag==1) //如果答案還是"Yes"那麽更新,這裏是一個優化~ flag = check(D,ver,edgeval) ; continue ; } else { onk[ver] = edgeval-onk[D] ; dfs(ver) ; } } } void PRINT(int* arr,int n) { for(int i=1; i<=n; ++i) { cout<<"arr["<<i<<"] = "<<arr[i]<<endl ; } } void sol() { flag = true ; read(n) , read(m) , read(k) ; //行的編號為1~n //列的編號為(n+1)~(2*n) //喵~ for(int i=1; i<=k; ++i) { int x,y,v ; read(x) , read(y) , read(v) ; add(x,y+n,v) ; add(y+n,x,v) ; } //cerr<<"FINISH READ"<<endl ; for(int i=1; i<=2*n; ++i) sort(edge[i].begin(),edge[i].end()) ; //cerr<<"FINISH SORT"<<endl ; for(int i=1; i<=2*n; ++i) { if(!inq[i]&&flag&&!edge[i].empty()) { // 註意這裏判一下vector是否為空。。因為這個RE了兩三次 onk[i] = (*edge[i].begin()).first ; //cerr<<"SEARCH IN DOT "<<i<<endl ; dfs(i) ; } } if(flag==1) { for(int i=1; i<=2*n; ++i) for(auto& j : edge[i]) if(flag==1) //重新check一遍,以免遺漏 flag = check(i,j.second,j.first) ; } if(flag) puts("Yes") ; else puts("No") ; //PRINT(onk,2*n) ; } void clear() { for(int i=1; i<=2*n; ++i) edge[i].clear() ; memset(inq,0,sizeof(onk)) ; memset(onk,0,sizeof(onk)) ; n = m = k = flag = 0 ; } } ; getsol M ; int T ; int main() { //freopen("solo3.in" , "rb" , stdin) ; //freopen("solo3.out", "wb" ,stdout) ; read(T) ; while(T--) M.sol() , M.clear() ; }
註意本代碼是使用C++11標準寫成,代碼中不同不同語法處已標註
題解【[FJOI2018]所羅門王的寶藏】