AOJ2338 よくわかる二重魔法
問題:
Intelligible Double Magic | Aizu Online Judge
要約すると、N頂点M辺の無向グラフが与えられるので好きに辺を有向にして(u,v)...uからvにいける ような組を多くせよ、という問題(N<=100,M<=N_C_2)
lowlinkを使って二重辺連結成分分解し重みつき木にしてdpすれば求めることができる
DEGwerが言っていたので考えてみたけど、ループの中身を見るとよくある木dp(O(n^3)と思いきやO(n^2)だった系の要素
(参考:二乗の木 DP - (iwi) { 反省します - TopCoder部)
があるのでO(n^4)->O(n^3)な気がする。違うかも。
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> pii; #define pb push_back #define mp make_pair #define rep(i,n) rep2(i,0,n) #define rep2(i,m,n) for(int i=m;i<(n);i++) int n,m; int szt[110],cmp[110],sz[110]; map<string,int> T; vector<int> g[110],g2[110]; pii es[5010]; int now,ret; int vis[110],ord[110],low[110],br[110][110]; void dfs(int v,int p){ vis[v]=1; ord[v]=low[v]=now++; for(int &to:g[v])if(to!=p){ if(!vis[to]){ dfs(to,v); low[v]=min(low[v],low[to]); if(ord[v]<low[to])br[v][to]=br[to][v]=1; }else low[v]=min(low[v],ord[to]); } } void dfs2(int v){ vis[v]=szt[v]=1; for(int &to:g[v]){ if(!vis[to]&&!br[v][to]){ dfs2(to); szt[v]+=szt[to]; } } } void dfs3(int v,int k){ sz[now]=k; cmp[v]=now; vis[v]=1; for(int &to:g[v]) if(!vis[to]&&!br[to][v]) dfs3(to,k); } int dp[110][110][110],m1[110][110],m2[110][110],wg[110]; void DFS(int v,int p){ dp[v][sz[v]][sz[v]]=sz[v]*sz[v]; wg[v]=sz[v]; for(int &to:g2[v])if(to!=p){ DFS(to,v); for(int i=wg[v];i;--i){ for(int j=wg[v];j;--j){ if(dp[v][i][j]==0)continue; for(int k=wg[to];k;--k){ int x=m1[to][k]; if(x)dp[v][i+k][j]=max(dp[v][i+k][j],dp[v][i][j]+x+j*k); x=m2[to][k]; if(x)dp[v][i][j+k]=max(dp[v][i][j+k],dp[v][i][j]+x+i*k); } } } wg[v]+=wg[to]; } rep(i,110)rep(j,110){ m1[v][i]=max(m1[v][i],dp[v][i][j]); m2[v][j]=max(m2[v][j],dp[v][i][j]); } } main(){ cin>>n>>m; string s; rep(i,n)cin>>s,T[s]=i; rep(i,m){ string a,b; cin>>a>>b; int p=T[a],q=T[b]; g[p].pb(q);g[q].pb(p); es[i]=mp(p,q); } dfs(0,-1); now=0; rep(i,n)vis[i]=0; rep(i,n)if(!vis[i])dfs2(i); rep(i,n)vis[i]=0; rep(i,n)if(!vis[i]){ dfs3(i,szt[i]); now++; } rep(i,m){ int p=cmp[es[i].first],q=cmp[es[i].second]; if(p!=q)g2[p].pb(q),g2[q].pb(p); } DFS(0,-1); rep(i,110)rep(j,110)ret=max(ret,dp[0][i][j]); cout<<ret<<endl; }