題面
這道題稍微想一想就會聯想到樹形dp的入門題:沒有上司的舞會;
但是再想一想會發現這根本就不是一顆樹,因為它比樹多了一條邊;
這時候我們引入乙個新的概念:基環樹;
顧名思義(??),基環樹就是在一顆樹上填一條邊構成的乙個圖;基環樹也叫環套樹(明明更像樹套環)。
我們在樹上可以做的事情基本都可以在基環樹上實現:比如樹形dp
基環樹的基本解題思路就是找到在環上的兩個點:s,t;
分別以s,t為根來跑一邊dp,這樣把兩次的答案進行處理就可以解決掉這道題;
那麼怎樣找環?我總結了幾種不同的思路:
1.並查集找環:對於要加入的兩個點如果已經在同乙個區域內,那麼他們一定在環上;
2.tarjan找環:對於乙個點,如果dfn[v]
3.dfs找環:其實和tarjan的基本思路一樣,如果乙個點的子節點v已經被經過,那麼u和v就在乙個環上;
#include #define int long longusing namespace std;
struct littlestarstar[2000010];
int head[2000010],cnt;
void add(int u,int v)
int ha[1000010],fa[1000010];
int f[1000010],g[1000010],vis[1000010];
void dfs(int u,int goal)
dfs(v,goal);
g[u]+=max(g[v],f[v]);
f[u]+=g[v];
}}int ans;
signed main()
for(register int i=1;i<=n;i++)
dfs(root,root);
int tmp=max(g[root],f[root]);
vis[root]=1;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
root=fa[root];
dfs(root,root);
tmp=max(tmp,max(g[root],f[root]));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
ans+=tmp;}}
cout《然後可以雙倍經驗:洛谷 p1453 城市環路
#include using namespace std;
struct littlestarstar[200010];
int head[200010],cnt;
void add(int u,int v)
int ha[100010],fa[100010];
double f[100010],g[100010];
void dfs(int u,int ff)
dfs(v,u);
f[u]+=g[v];
g[u]+=max(g[v],f[v]);
}}inline int zhaobaba(int x)
int s,t;
int main()
add(u,v);
add(v,u);
fa[zhaobaba(v)]=zhaobaba(u);
}double ans=0,k;
scanf("%lf",&k);
dfs(s,0);
ans=g[s];
dfs(t,0);
ans=max(ans,g[t]);
printf("%.1lf",ans*k);
}
ZJOI2008 騎士 基環樹
題意見鏈結。本題較為經典,值得一做。基環外向樹練手好題。如果不考慮環的情況,則就是普通樹形dp,f i 0 1 表示這個點取或不取。對於此題一棵樹只能出現乙個環,我們任意刪去環上的一條邊,即可轉環為樹。對於 u,v 1 u 不取,則以 u 為根dp。2 v 不取,則以 v 為根dp。不需要考慮兩個點...
ZJOI2008 騎士(基環樹 DP)
看似有向邊,其實可以轉化為無向邊。構成乙個基環森林 但是需要特判一種情況 當有兩個人互相討厭的時候,形成一棵樹,同時有重邊 我的找環做法需要sort判重,可能有更好的方法 然後把森林裡的每一棵樹或者基環樹dp一下 就是沒有上司的舞會模型,超水 把答案加起來 注意會爆int 做完了 include i...
ZJOI2008 泡泡堂題解
一道博弈論貪心題 如下 213 242 06 10000000 10000000 10000000 10000000 10000000 1000000000 000012 12我們分別稱 4 位選手為 a,b,c,d 則可能出現以下 4 種對戰方式,最好情況下可得 2 分,最壞情況下得 0 分。浙江...