RP路

RP

題目描述

XRP十分有研究,現在他向你提出了一個問題。給出一棵N個節點的樹,有些邊是RP邊,至少經過一條RP邊的路徑定義爲RP路,其他路徑定義爲非RP路。現在,你需要令最多一條RP邊變爲非RP邊,使得RP路的數量最少。
數據範圍

測試點 N
1~2 ≤100
3~5 ≤5 000
6 ≤10 000
7~10 ≤100 000

輸入格式 2074.in

第一行一個正整數N

接下來N-1行,每行三個整數A,B,C。表示節點A,B間存在一條邊,如果是RP邊,那麼C=1,否則C=0。節點從1開始到N標號。

輸出格式 2074.out

一個表示你的答案的整數。

輸入樣例 2074.in

5
3 5 1
1 4 1
5 2 1
2 1 0

輸出樣例 2074.out

7

       這題,涉及到一種轉化思想。基本思路如下:我們直接求RP路徑有多少條,不太好求,直接求是N*N的。那就將其轉化成總路徑條數減去非RP路徑條數,這就是初始RP路徑條數。然後,分別計算,去掉每條RP邊,會減少的RP路徑條數。初始RP路徑條數減去這其中的最大值即爲所求。

   總路徑條數?自然是N*(N-1)/2。

   那麼,非RP路徑如何求?根據定義,非RP路徑中的所有邊皆爲非RP邊,其中不能有RP邊。通過手動畫RP樹可以發現,可以將原圖進行“縮點”,縮成以RP路爲樹邊,以非RP子集爲結點的樹。(縮點可用並查集/DFS)。所有新點內部的路徑數之和即爲非RP路徑總數。

   去掉每條RP邊,會減少的RP路徑條數如何求?明確一點:會被減少的RP路徑,路徑中有且只有一條RP邊,就是被刪的那條。因此不難發現,會減少的RP路徑條數,等於此RP邊所連接的兩非RP子集的結點乘積。

   至此,題目所求可以求出。

   說白了,此題我沒有想出的原因,就是沒有想到這樣“縮點”。因此,觀察特徵,總結潛在規律,打開思路解題很重要。。。。造化不夠。。。。。……

   代碼如下:

#include
#include
#include
using namespacestd;
const intMAXN=1e5+5;
struct poi
{
       int to,type;
};
vectoredge[MAXN];
long longn,a,b,c,f[MAXN],v[MAXN],father[MAXN],vi[MAXN];
long longans,minu;
int findA(int x)
{
       if(father[x]==x)      return x;
       return father[x]=findA(father[x]);
}
void init(inta,int b,int c)
{
       edge[a].push_back((poi){b,c});
       edge[b].push_back((poi){a,c});
       if(c==0)
       {
              int root1=findA(a),root2=findA(b);
              father[root1]=root2;
       }
}
void dfs(intnow)
{
       vi[now]=1;
       int size=edge[now].size();
       for(int i=0;i>n;
       for(int i=1;i<=n;i++)      father[i]=i;
       for(int i=1;i>a>>b>>c;
              init(a,b,c);
       }
       for(int i=1;i<=n;i++)
       {
              int root=findA(i);
              father[i]=root;
              v[father[i]]++;
       }
       ans=n*(n-1)/2;
       for(int i=1;i<=n;i++)      ans-=v[i]*(v[i]-1)/2;
       minu=0;
       dfs(1);
       cout<


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章