首先我們要思考乙個問題, 公交線路要加到什麼程度才能夠使得任意兩個點兩兩可達
很容易知道每個點和他的父親必須兩兩可達
所以最終所有公交線路新增的邊其實就是把原來的邊全部反向
那麼這些邊要如何組成公交線路呢, 必須要滿足, 在這條公交線路中, 邊的指向相同, 要麼都向上, 要麼都向下, 或者原來向上, 在某個點轉成向下, 也可以反過來
我們既然要使得公交線路數最短, 就要使只向上的和只向下的路徑長度盡量長, 並且要是更多的向上和向下的路徑在某個點相交
那麼我們就可以得到這樣乙個貪心策略
對於乙個點, 我們先盡量讓向上的和向下的相抵消, 那麼最多一種會剩下來, 然後再看這一種和這個點向父親連的邊的方向是不是一樣的
如果是, 就把他傳上去, 看能不能再跟其他的匹配
如果不是, 那他傳不了了, 就只能到這裡打止
這樣一定是最優的, 如果你當前不把能匹配的匹配完了, 上去匹配的話, 可能沒有可以和你匹配的
但如果你在這裡就匹配了的話, 公交線路數量至少不會變多
所以這樣是最優的
#include #include #include #include const int n = 100005;
using namespace std;
int n, st[n], ed[n], head[n], ans, g[n], up[n], down[n], cnt, dep[n], id[n];
struct edge e[n << 1];
template < typename t >
inline t read()
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}inline void adde(int u, int v) , head[u] = cnt; }
void dfs1(int u, int fa)
}void dfs(int u, int fa)
int tmp = min(down[u], up[u]);
ans += tmp, down[u] -= tmp, up[u] -= tmp;
if(u == 1) ans += up[u] + down[u];
else ans += id[u] == 1 ? up[u] : down[u];
g[u] = max(1, id[u] == 1 ? down[u] : up[u]);
}int main()
dfs1(1, 0);
for(int i = 1; i < n; i++)
if(dep[st[i]] < dep[ed[i]])
id[ed[i]] = 1;
else id[st[i]] = 2;
dfs(1, 0);
printf("%d\n", ans);
return 0;
}
JSOI2013 旅行時的困惑
傳送門 由於我們的圖不僅是乙個 text 而且在形態上還是一棵樹,也就是說我們為了實現節點之間互相可達,就必須把每條邊都覆蓋一次,因為兩個點之間的路徑是唯一的。那麼題意就變成了 每次在圖上選出一條路徑,覆蓋上面的邊,求最小的路徑數使得所有邊都被覆蓋至少一次。看到這裡我不禁聯想起這道題 那麼對於這道題...
JSOI2013 快樂的 JYY 題解
題面傳送門 我們一句話題意 求兩個字串的公共回文子串的數量 首先對於每個串構造乙個回文自動機,然後由pam的定義可知 對於pam上從根節點轉移方式相同所到達的點代表的回文串是相同的 這樣對於兩個pam同時dfs,每次dfs到的節點的數值 在其原串中的出現數量 相乘,然後累加到答案裡 注意 要從偶原點...
題解 JSOI2013 哈利波特與死亡聖器
轉化問題,即乙個點從根節點往下走,到達任意乙個點時,保證每乙個與他直接連通的點都被覆蓋了 沒有必要向上走,因為這只會留更多時間來修復 所以我們討論只下不上的情況 二分乙個 mid 代表當前共有 mid 個人 設 f i 為到了 i 點,且 i 的兒子全部未被覆蓋,需要之前多少次額外的來覆蓋 有 f ...