纸牌 最小生成树
紙牌
時間限制:?1 Sec??內(nèi)存限制:?128 MB
題目描述
有n張牌,每個牌有一個a屬性和1個b屬性,第i張牌的屬性為ai,bi。現(xiàn)在每次從牌中選兩張牌i,j,得到一個ai * bj + bi * aj的分數(shù),然后從這兩張牌中去掉1張牌。經(jīng)過n-1次操作之后就剩1張牌了。問經(jīng)過n-1次操作后得到的最大的分數(shù)和是多少。
輸入
首行輸入n,代表n個點
接下來n行,每一行兩個屬性ab第i行代表第i張牌,屬性為ai,bi。數(shù)據(jù)范圍保持在200以內(nèi)。
輸出
輸出最大分數(shù)
樣例輸入
5 2 4 3 3 1 7 2 5 4 4樣例輸出
108題解
艾神講過的最小生成樹經(jīng)典題目,主要是刪除牌的問題。但是假如我們將每張牌看成1個結(jié)點,兩個點的屬性的乘積得到的分數(shù)為1條路徑長度,那么n個結(jié)點構(gòu)成了n*(n-1)/2條邊的強聯(lián)通無向圖,那么只需求每次分數(shù)最大的最小生成樹即可。
#include<bits/stdc++.h> using namespace std; const int maxn = 1007; int a[maxn],b[maxn]; int n; struct edge {int u,v,w;bool friend operator <(edge a,edge b){return a.w<b.w;} }; priority_queue<edge> q; int pre[maxn]; int get_parent(int x) {if(pre[x]==-1) return x;return pre[x]=get_parent(pre[x]); } bool mix(int x,int y) {int fx=get_parent(x),fy=get_parent(y);if(fx==fy) return 1;pre[fx]=fy;return 0; } int kruskal() {int cost=0;while(!q.empty()){edge x=q.top();q.pop();if(!mix(x.u,x.v))cost+=x.w;}return cost; } int main() {memset(pre,-1,sizeof(pre));scanf("%d",&n);for(int i=0;i<n;i++)scanf("%d%d",&a[i],&b[i]);for(int i=0;i<n;i++)for(int j=0;j<i;j++){edge t;t.u=i;t.v=j;t.w=a[i]*b[j]+a[j]*b[i];q.push(t);}cout<<kruskal()<<endl; }?
總結(jié)
- 上一篇: 躁动的小Z 最短路+路径记录
- 下一篇: 逛街 最短距离+花费