習題:Vasya and Maximum Matching(轉換&DP)
阿新 • • 發佈:2020-07-31
題目
思路
這道題的難點主要在於模型的轉換
我們首先考慮一顆樹的如果有唯一最大匹配會滿足什麼條件
每一個葉子是一個被匹配到的(這應該不難證明吧)
接著我們考慮將每一對匹配的節點刪去,那麼最後一定不會剩下任何節點(你可以平移的思想去證明)
當然,還是有唯一的例外的,這個樹只有一個節點
接著我們設\(dp[i][3]\)表示以i為根節點的子樹,0表示i已經和某一個兒子匹配了,1表示i不和任何一個兒子進行匹配,但是他與父親進行了匹配,2表示i不和任何一個兒子進行匹配,這裡不要求和父親之間的關係
接著我們考慮用插入的方法來合併dp,即將v節點前面所列舉的節點看做是一顆子樹
如果是0,那麼他可能之前就已經匹配好,或者是與v進行匹配
如果是1,那麼兒子節點要麼匹配好了,要麼就是一個點或者自己以前就是無子的情況
如果是2,就更簡單了,直接考慮兒子匹配好了,或者無子就行
程式碼
#include<iostream> #include<vector> using namespace std; const int mod=998244353; int n; long long dp[300005][3]; /* 0:匹配 1:未被匹配,但是父親和他進行匹配 2:無子 */ long long temp[3]; vector<int> g[300005]; void dfs(int u,int fa) { dp[u][2]=1; for(int i=0;i<g[u].size();i++) { int v=g[u][i]; if(v!=fa) { dfs(v,u); temp[0]=dp[u][0]*(dp[v][0]*2+dp[v][2])%mod; temp[0]=(temp[0]+(dp[u][1]+dp[u][2])*(dp[v][1]+dp[v][2])%mod)%mod; temp[1]=dp[u][2]*dp[v][0]%mod; temp[1]=(temp[1]+dp[u][1]*(dp[v][0]*2+dp[v][2]))%mod; temp[2]=(dp[u][2]*(dp[v][2]+dp[v][0]))%mod; for(int j=0;j<=2;j++) dp[u][j]=temp[j]; } } } int main() { cin>>n; for(int i=1,u,v;i<n;i++) { cin>>u>>v; g[u].push_back(v); g[v].push_back(u); } dfs(1,0); cout<<(dp[1][0]+dp[1][2])%mod; return 0; }