題目鏈接
http://codeforces.com/contest/260/problem/D
題目大意
給你一棵樹(注意不要出現環)的所有節點, 節點分爲黑、白兩類,只有不同顏色的節點才能相連, 每個節點還有一個值, 該值表示該點所連邊的權值之和, 最後讓你輸出每條邊所連的兩個節點以及其權值(題目爲特判)
思路
該題幾乎沒有用到算法,但十分考驗思維
首先sum(edge) = sum(node)
由於只有不同顏色的node才能相連, 所以sum(white) = sum(black)
由這兩個式子我們可以得出這麼一個結論:從一個節點出發, 取另一種顏色的另一個節點, 我們把較小的值作爲該邊的權值,那麼較大的就要減去這個權值, 再用已經減過的值繼續遞歸地找另一種顏色的節點, 這樣一定可以組成一張符合題意的樹, 如果還有節點沒有使用,那麼該節點的值一定爲0, 否則就無法加入樹中
有很多題解都是排序後貪心找, 其實不用排序, 直接dfs就好了
代碼
#include<bits/stdc++.h>
using namespace std;
const int M = 1e5 + 5;
struct node
{
int id, val;
bool operator < (node & x)
{
return val < x.val;
}
};
queue<node>b;
queue<node>w;
struct edg
{
int l, r, val;
};
vector<edg>ans;
void dfs(node v, bool c)
{
if(c)
{
while(!b.empty())
{
node tmb = b.front();
b.pop();
edg tmp;
if(tmb.val >= v.val)
{
tmp.l = v.id;
tmp.r = tmb.id;
tmp.val = v.val;
ans.push_back(tmp);
tmb.val -= v.val;
dfs(tmb, 0);
return ;
}
tmp.l = tmb.id;
tmp.r = v.id;
tmp.val = tmb.val;
ans.push_back(tmp);
v.val -= tmb.val;
}
}
else
{
while(!w.empty())
{
node tmw = w.front();
w.pop();
edg tmp;
if(tmw.val > v.val)
{
tmp.l = v.id;
tmp.r = tmw.id;
tmp.val = v.val;
ans.push_back(tmp);
tmw.val -= v.val;
dfs(tmw, 1);
return ;
}
tmp.l = tmw.id;
tmp.r = v.id;
tmp.val = tmw.val;
ans.push_back(tmp);
v.val -= tmw.val;
}
}
}
int main()
{
int n;
scanf("%d", &n);
int tb = 0, tw = 0;
for(int i=1; i<=n; ++i)
{
int c, v;
scanf("%d%d", &c, &v);
if(c)
{
node tmp;
tmp.id = i;
tmp.val = v;
b.push(tmp);
}
else
{
node tmp;
tmp.id = i;
tmp.val = v;
w.push(tmp);
}
}
int rw = w.front().id, rb = b.front().id;
node temp = b.front();
b.pop();
dfs(temp, 0);
while(w.size()) //注意最後可能還有節點沒有用完,這些沒用完的節點的值一定是0,否則那兩個式子就不成立了
{
node tmw = w.front();
w.pop();
edg tmp;
tmp.l = tmw.id;
tmp.r = rb;
tmp.val = 0;
ans.push_back(tmp);
}
while(b.size())
{
node tmb = b.front();
b.pop();
edg tmp;
tmp.l = tmb.id;
tmp.r = rw;
tmp.val = 0;
ans.push_back(tmp);
}
int len = ans.size();
for(int i=0; i<len; ++i)
{
printf("%d %d %d\n", ans[i].l, ans[i].r, ans[i].val);
}
return 0;
}