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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

夯实基础项目工程之图论——Uncle Bogdan and Country Happiness,Graph Coloring,How Many Paths?,Array Differentiation

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 夯实基础项目工程之图论——Uncle Bogdan and Country Happiness,Graph Coloring,How Many Paths?,Array Differentiation 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 做題情況項目報告
  • Uncle Bogdan and Country Happiness
  • Graph Coloring
  • How Many Paths?
  • Array Differentiation

做題情況項目報告

T1,T3T1,T3T1,T3一眼題,在實現上,T3T3T3耗時略長(有些情況未考慮到位)

T4T4T4感覺題,一眼隱隱約約有正解的思路

T2T2T2感覺題,思考到二分圖性質后,并未往DPDPDP上想

Uncle Bogdan and Country Happiness

CD1388C

rating:1800 簡單題

給出一顆根節點為111的樹,對于每個節點iii,有pip_ipi?個人的家在節點iii

一開始所有人都在根節點上,然后每個人會往家沿著最短路走

每個人出發時有一個心情,可能是好心情也可能是壞心情,在經過一條邊時,心情可能由好變壞,但是不可能由壞變好

每個點有一個幸福檢測器,最后的檢測結果為:所有經過該節點的人中,好心情的人數減壞心情的人數

現在給出hih_ihi?,問有沒有可能最后每個節點的檢測結果恰好hih_ihi?


solution

observation1 : 這是一棵以111為根的樹,經過每個點的人數是固定的,即為子樹內居住人數大小,記為sizi\rm siz_isizi?

observation2 : 由于心情變化規則可知,父親的壞心情人數一定不小于直系兒子壞心情人數和

所以直接dfs樹一遍,根據good+bad=sizi,good?bad=hi\rm good+bad=siz_i,good-bad=h_igood+bad=sizi?,good?bad=hi?,可以求得經過每個點時的好壞心情人數,然后根據壞心情人數是否夠判斷


#include <cstdio> #include <vector> using namespace std; #define maxn 100005 vector < int > G[maxn]; int T, n, m, flag; int p[maxn], h[maxn], bad[maxn], siz[maxn];void dfs1( int u, int fa ) {siz[u] = p[u];for( auto v : G[u] )if( v == fa ) continue;else dfs1( v, u ), siz[u] += siz[v];bad[u] = ( siz[u] - h[u] ) >> 1; }void dfs2( int u, int fa ) {int cnt = 0;for( auto v : G[u] ) {if( v == fa ) continue;else dfs2( v, u ), cnt += bad[v];}if( cnt + p[u] < bad[u] ) flag = 1; }int Fabs( int x ) { return x < 0 ? -x : x; }int main() {scanf( "%d", &T );next :while( T -- ) {scanf( "%d %d", &n, &m );flag = 0;for( int i = 1;i <= n;i ++ )G[i].clear(), siz[i] = bad[i] = 0;for( int i = 1;i <= n;i ++ )scanf( "%d", &p[i] );for( int i = 1;i <= n;i ++ )scanf( "%d", &h[i] );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs1( 1, 0 );for( int i = 1;i <= n;i ++ )if( ( ( siz[i] - h[i] ) & 1 ) or ( siz[i] < Fabs( h[i] ) ) ) {printf( "NO\n" );goto next;}dfs2( 1, 0 );if( flag ) printf( "NO\n" );else printf( "YES\n" );}return 0; }

Graph Coloring

CF1354E

rating 2100: 中檔題

現有一張nnn個節點mmm條邊的無向圖,要求用{1,2,3}\{1,2,3\}{1,2,3}對每個點染色,使得相鄰的兩個點的權值的絕對值之差剛好111

現在需要求出一個方案,使得一共染了n1n_1n1?111n2n_2n2?222n3n_3n3?333,保證n1+n2+n3=nn_1+n_2+n_3=nn1?+n2?+n3?=n

無解則輸出NO\rm NONO;否則輸出YES\rm YESYES并輸出一個字符串,其中第iii位表示節點iii的顏色


solution

observation1: 各連通塊之間互不影響,所以可以分連通塊求解

observation2: 1/3只能和2相鄰,所以這張圖一定是個二分圖,并且2一定是全為一種顏色(黑色/白色)

dfs遍歷圖,判斷是否是二分圖

至于222必須是同種顏色,分連通塊就可以設計dpdpdp轉移了

dfs求出連通塊黑白顏色的個數及分別是哪些點

dpi,j:dp_{i,j}:dpi,j?: 到第iii個連通塊被標記222的點數個數為jjj是否存在一種方案可行

dpi,j=dpi?1,j?cnt0,i∣dpi?1,j?cnt1,idp_{i,j}=dp_{i-1,j-cnt_{0,i}}|dp_{i-1,j-{cnt_{1,i}}}dpi,j?=dpi?1,j?cnt0,i??dpi?1,j?cnt1,i??

只要最后dpcnt,n2=1dp_{cnt,n2}=1dpcnt,n2?=1就一定有解

剩下就是很簡單的根據dpdpdp倒著回去構造解了,先把所有的222找到,剩下的就是1,31,31,3無所謂了

倒回去看轉移的兩個dpdpdp哪個是可行的


#include <cstdio> #include <vector> #include <cstring> #include <iostream> using namespace std; #define maxn 5005 vector < int > G[maxn], G0[maxn], G1[maxn]; int n, m, n1, n2, n3, cnt; int c[maxn], ans[maxn]; bool dp[maxn][maxn]; bool vis[maxn], MS[maxn];void dfs1( int u ) {for( auto v : G[u] ) {if( ! ~ c[v] ) {c[v] = c[u] ^ 1;dfs1( v );}else if( c[u] == c[v] ) {printf( "NO\n" );exit( 0 );}} }void dfs2( int u ) {vis[u] = 1;if( c[u] ) G1[cnt].push_back( u );else G0[cnt].push_back( u );for( auto v : G[u] )if( ! vis[v] ) dfs2( v ); }int main() {scanf( "%d %d %d %d %d", &n, &m, &n1, &n2, &n3 );for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u ); }memset( c, -1, sizeof( c ) );for( int i = 1;i <= n;i ++ )if( ! ~ c[i] ) c[i] = 0, dfs1( i );for( int i = 1;i <= n;i ++ )if( ! vis[i] ) cnt ++, dfs2( i );dp[0][0] = 1;for( int i = 1;i <= cnt;i ++ )for( int j = 0;j <= n;j ++ ) {if( G0[i].size() <= j )dp[i][j] |= dp[i - 1][j - G0[i].size()];if( G1[i].size() <= j )dp[i][j] |= dp[i - 1][j - G1[i].size()];}if( ! dp[cnt][n2] ) return ! printf( "NO\n" );else printf( "YES\n" );int now = n2;for( int i = cnt;i;i -- ) {if( now >= G0[i].size() and dp[i - 1][now - G0[i].size()] )MS[i] = 0, now -= G0[i].size();else if( dp[i - 1][now - G1[i].size()] )MS[i] = 1, now -= G1[i].size();}for( int i = 1;i <= cnt;i ++ ) if( MS[i] )for( auto j : G1[i] )ans[j] = 2;else for( auto j : G0[i] )ans[j] = 2;for( int i = 1;i <= n;i ++ )if( ! ans[i] ) {if( now < n1 ) ans[i] = 1, now ++;else ans[i] = 3;}for( int i = 1;i <= n;i ++ ) printf( "%d", ans[i] );return 0; }

How Many Paths?

CF1547G

有一個有向圖,圖中含有nnn個點mmm條邊(邊中可能有自環,但是沒有重邊)

設頂點iii的答案為ansians_iansi?,則:

  • 如果不存在一條111iii的路徑,ansians_iansi?000
  • 如果只存在一條111iii的路徑,ansians_iansi?111
  • 如果至少存在兩條111iii的路徑,并且路徑數量是有限的,ansians_iansi?222
  • 如果存在無限條111iii的路徑,ansians_iansi??1-1?1

注意路徑不必是簡單路徑

對于每一個1≤i≤n1 \leq i \leq n1in,輸出ansians_iansi?


observation1: 不必是簡單路徑,所以可以到處繞彎

observation2: 只要存在一條路上有環,那么到iii的路徑就一定是無線條

自環特殊記錄一下

tarjan縮點,對縮點后的狀態建圖,同一個連通塊內的邊不再出現

連通塊內點數>1>1>1或者有自環標記說明該連通塊是環,連出去的邊,邊權?1-1?1;否則邊權000

111所在的連通塊scc[1]開始跑堆優化dijkstra最短路

并記錄經過iii的次數vis[i]

如果iii的路徑長為inf證明到達不了,沒有路徑

如果路徑長為負數,說明有至少一條路徑上有環,則是無限條路徑

堆優化dijkstra最短路記錄經過次數后,直接判斷是否>1>1>1是不對的

因為寫法會導致,多次經過某點時,若沒有最短路更新是不會入隊,也就不會使得后面的點的經過次數增加

也就是說經過次數其實維護的是假的

在記錄一個pre[i]表示最短路iiipreipre_iprei?更新

最后倒著往前面找,然后vis[i]取一路上的最大值

這樣雖然維護的還是假的真正經過次數,但是就已經可以區別出是只經過一次還是更多次,我們也沒有必要找到真正經過了多少次iii

#include <stack> #include <queue> #include <cstdio> #include <vector> #include <iostream> using namespace std; #define inf 0x3f3f3f3f #define maxn 400005 struct node {int to, w;node(){}node( int To, int W ) { to = To, w = W; }bool operator < ( const node &t ) const { return w > t.w; } }; struct edge {int u, v;edge(){}edge( int U, int V ) { u = U, v = V; } }E[maxn]; priority_queue < node > q; stack < int > sta; vector < node > g[maxn]; vector < int > G[maxn], cnt[maxn]; int T, n, m, ip, tot; int dfn[maxn], low[maxn], dis[maxn], vis[maxn], scc[maxn], cir[maxn], pre[maxn], gone[maxn];void tarjan( int u ) {dfn[u] = low[u] = ++ ip, sta.push( u );for( auto v : G[u] ) {if( ! dfn[v] ) { tarjan( v ); low[u] = min( low[u], low[v] ); }else if( ! scc[v] ) low[u] = min( low[u], dfn[v] );}if( low[u] == dfn[u] ) {++ tot; int v;do {v = sta.top(), sta.pop(), scc[v] = tot;cnt[tot].push_back( v );} while( v != u );} }void find( int i ) {if( ! i or gone[i] ) return;else gone[i] = 1, find( pre[i] ), vis[i] = max( vis[i], vis[pre[i]] ); }int main() {scanf( "%d", &T );int Case;while( T -- ) {scanf( "%d %d", &n, &m );ip = tot = 0;while( ! q.empty() ) q.pop();while( ! sta.empty() ) sta.pop();for( int i = 1;i <= n;i ++ ) {cnt[i].clear(), G[i].clear(), g[i].clear();dfn[i] = vis[i] = cir[i] = scc[i] = gone[i] = pre[i] = 0, dis[i] = inf;}int Edge = 0;for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );if( u == v ) cir[u] = 1;else G[u].push_back( v ), E[++ Edge] = edge( u, v );}for( int i = 1;i <= n;i ++ )if( ! dfn[i] ) tarjan( i );for( int i = 1;i <= Edge;i ++ )if( scc[E[i].u] ^ scc[E[i].v] ) {if( cir[E[i].u] or cir[E[i].v] or cnt[scc[E[i].u]].size() > 1 or cnt[scc[E[i].v]].size() > 1 )g[scc[E[i].u]].push_back( node( scc[E[i].v], -1 ) );elseg[scc[E[i].u]].push_back( node( scc[E[i].v], 0 ) );}dis[scc[1]] = cnt[scc[1]].size() > 1 ? -1 : 0;q.push( node( scc[1], 0 ) );vis[scc[1]] ++;while( ! q.empty() ) {int u = q.top().to; q.pop();for( int i = 0;i < g[u].size();i ++ ) {int v = g[u][i].to, w = g[u][i].w;vis[v] ++;if( dis[v] < 0 ) continue; if( dis[u] + w < dis[v] ) {dis[v] = dis[u] + w, pre[v] = u;q.push( node( v, dis[v] ) );}}}gone[scc[1]] = 1;for( int i = 1;i <= tot;i ++ ) find( i );for( int i = 1;i <= n;i ++ )if( dis[scc[i]] == inf ) printf( "0 " );else if( dis[scc[i]] < 0 or cir[i] or cnt[scc[i]].size() > 1 ) printf( "-1 " );else if( vis[scc[i]] > 1 ) printf( "2 " );else printf( "1 " );printf( "\n" );}return 0; }

Array Differentiation

CF1552D

ttt組數據,每一組給定一個數組{an}\{a_n\}{an?},問是否存在這樣一個數組{bn}\{ b_n \}{bn?},對于所有i∈[1,n]i \in [1,n]i[1,n],都存在一組j、k∈[1,n]j、k\in[1,n]jk[1,n],滿足ai=bj?bka_i=b_j-b_kai?=bj??bk?

1<=n<=10


solution

如果把bib_ibi?當成點權,建構一棵樹,使得aja_jaj?恰好等于樹上的邊權

那么最后剩下的aja_jaj?就會使得樹變成一張圖,并不是一個環,因為這是有向邊

但是如果這其中的某些邊取反,似乎就能成為一個環

nnn的范圍那么小基本鎖定正解就是3n3^n3n暴搜,取反某些aia_iai?的值?ai-a_i?ai?,然后存在某些aaa的和為000


#include <cstdio> #include <algorithm> using namespace std; int T, n, flag; int a[15];void dfs( int x, int sum, int cnt ) {if( sum == 0 and cnt ) {flag = 0;return;}if( x > n ) return;if( flag ) dfs( x + 1, sum, cnt );if( flag ) dfs( x + 1, sum + a[x], cnt + 1 );if( flag ) dfs( x + 1, sum - a[x], cnt + 1 ); }int main() {scanf( "%d", &T );next :while( T -- ) {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] );sort( a + 1, a + n + 1 );for( int i = 1;i < n;i ++ )if( a[i] == a[i + 1] ) {printf( "YES\n" );goto next;}n = unique( a + 1, a + n + 1 ) - a - 1;flag = 1;dfs( 1, 0, 0 );if( flag ) printf( "NO\n" );else printf( "YES\n" );}return 0; }

總結

以上是生活随笔為你收集整理的夯实基础项目工程之图论——Uncle Bogdan and Country Happiness,Graph Coloring,How Many Paths?,Array Differentiation的全部內容,希望文章能夠幫你解決所遇到的問題。

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