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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

匹配(树形DP)

發布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 匹配(树形DP) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

題目描述:

有一張無向聯通圖 G=?V,E? ,其中頂點數 |V|=n ,邊數 |E|=n?1 。求有多少種方案使得刪邊后殘余圖中的最大匹配數恰好為 m 的倍數。

題解:

這道題看起來是求最大匹配,其實關系不大,正解是樹形DP

定義一個數組dp[i][j][k], 其中

i表示節點,

j表示i的子樹中的最大匹配數%m,

k表示i是否與其子節點匹配.

接下來推一下合并兩顆子樹u,v的遞推式即可

注意幾個細節:

1.用快讀,否則會TLE

2.盡量少取余,否則會很慢

3.有2n條邊,我一開始就因為數組開小了卡了很久

4.dp[i][j][k]上一次的結果不帶入這一次,要另開一個tmp數組來執行操作

#include<iostream> #include<cstdio> using namespace std; typedef long long ll; inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } const int N=50010; const int M=200; const int mod=998244353; int n,m; struct Edge{int v,nxt; }edge[N<<1]; ll dp[N][M][2],tmp[M][2]; int head[N],cnt,fa[N],sz[N]; void add_edge(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt; } void dfs(int u){sz[u]=1;dp[u][0][0]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa[u]) continue;fa[v]=u;dfs(v);for(int i=0;i<m;i++) tmp[i][0]=tmp[i][1]=0;for(int j=0;j<=sz[u]&&j<m;j++){for(int k=0;k<=sz[v]&&k<m;k++){int v1=(j+k+1)%m,v2=(j+k)%m;tmp[v1][1]+=dp[u][j][0]*dp[v][k][0];tmp[v1][1]%=mod;tmp[v2][0]+=dp[u][j][0]*dp[v][k][0]+dp[u][j][0]*dp[v][k][1]*2;tmp[v2][0]%=mod;tmp[v2][1]+=dp[u][j][1]*dp[v][k][0]*2+dp[u][j][1]*dp[v][k][1]*2;tmp[v2][1]%=mod;}}for(int i=0;i<m;i++){dp[u][i][0]=tmp[i][0];dp[u][i][1]=tmp[i][1];}sz[u]+=sz[v];} } int main(){n=read();m=read();for(int i=1;i<n;i++){int u=read();int v=read();add_edge(u,v);add_edge(v,u);}dfs(1);printf("%d\n",(dp[1][0][0]+dp[1][0][1])%mod);return 0; }

總結

以上是生活随笔為你收集整理的匹配(树形DP)的全部內容,希望文章能夠幫你解決所遇到的問題。

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