【POJ - 3723 】Conscription(最小生成樹)

Conscription

Descriptionsios

須要徵募女兵N人,男兵M人。 每招募一我的須要花費10000美圓。 若是已經招募的人中有一些關係親密的人,那麼能夠少花一些錢。 給出若干男女以前的1 ~ 9999 之間的親密度關係, 招募某我的的費用是 10000 - (已經招募了的人中和本身的親密度的最大值)。 要求經過適當的招募順序使得招募全部人所花費的費用最小。算法

Input測試

輸入N, M, R;
接下來輸入R行 (x, y, d) 表示第 x 號男兵和第 y 號女兵之間的親密度是 dspa

Output.net

輸入最小花費的值。code

Sample Inputblog

2排序

5 5 8
4 3 6831
1 3 4583
0 0 6592
0 1 3063
3 3 4975
1 3 2049
4 2 2104
2 2 781ip

5 5 10
2 4 9820
3 2 6236
3 1 8864
2 4 8326
2 0 5156
2 0 1463
4 1 2439
0 4 4373
3 4 8889
2 4 3133ci

Sample Output

71071
54223

題目連接

https://vjudge.net/problem/POJ-3723

把人當作點,關係看做邊,轉化爲求解無向圖的最大權森林問題,這個問題又能夠經過把全部邊取反以後用最小生成樹的算法求解

典型的kruskal算法

注意要用scanf printf

AC代碼

 

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define IOS                       \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
#define Mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f
#define MEM(x, y) memset(x, y, sizeof(x))
#define Maxn 1000000 + 10
using namespace std;
int N, M, R;
int x[Maxn], y[Maxn], d[Maxn];//男孩 女孩 關係度
struct edge
{
    int u, v, cost;//u到v的距離爲cost
};
bool cmp(const edge &e1, const edge &e2)//從小到大排序
{
    return e1.cost < e2.cost;
}
edge es[Maxn];
int par[Maxn];
void init(int n)//初始化並查集
{
    for (int i = 0; i <= n; i++)
        par[i] = i;
}
int findr(int x)//尋根
{
    if (par[x] == x)
        return x;
    return par[x] = findr(par[x]);
}
void unite(int x, int y)//合併
{
    x = findr(x);
    y = findr(y);
    if (x == y)
        return;
    par[x] = y;
}
bool same(int x, int y)//判斷根是否相同
{
    return findr(x) == findr(y);
}
int kruskal(int V, int E)//kruskal算法求最小生成樹
{
    sort(es, es + E, cmp);
    init(V);
    int res = 0;
    for (int i = 0; i < E; i++)
    {
        edge e = es[i];
        if (!same(e.u, e.v))
        {
            unite(e.u, e.v);
            res += e.cost;
        }
    }
    return res;
}
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)//T組測試樣例
    {
        scanf("%d%d%d", &N, &M, &R);//存數據
        for (int i = 0; i < R; i++)
            scanf("%d%d%d", &x[i], &y[i], &d[i]);
        int V, E;
        V = N + M;//頂點個數
        E = R;//邊個數
        for (int i = 0; i < E; i++)//存入結構體
        {
            es[i] = (edge){
                x[i], N + y[i], -d[i]};
        }
        printf("%d\n", 10000 * (N + M) + kruskal(V, E));
    }
    return 0;
}

 

 

 

#include  <iostream>
#include  <cstdio>
#include  <fstream>
#include  <algorithm>
#include  <cmath>
#include  <deque>
#include  <vector>
#include  <queue>
#include  <string>
#include  <cstring>
#include  <map>
#include  <stack>
#include  <set>
#include  <sstream>
#define  IOS                        \
     ios_base:: sync_with_stdio( 0);  \
     cin. tie( 0);
#define  Mod  1000000007
#define  eps  1e - 6
#define  ll  long  long
#define  INF  0x3f3f3f3f
#define  MEM (x, y)  memset(x, y,  sizeof(x))
#define  Maxn  1000000  +  10
using  namespace  std;
int N, M, R;
int  x[Maxn],  y[Maxn],  d[Maxn]; //男孩 女孩 關係度
struct  edge
{
     int u, v, cost; //u到v的距離爲cost
};
bool  cmp( const edge  & e1const edge  & e2) //從小到大排序
{
     return  e1. cost  <  e2. cost;
}
edge  es[Maxn];
int  par[Maxn];
void  init( int  n) //初始化並查集
{
     for ( int i  =  0; i  <= n; i ++)
         par[i]  = i;
}
int  findr( int  x) //尋根
{
     if ( par[x]  == x)
         return x;
     return  par[x]  =  findr( par[x]);
}
void  unite( int  xint  y) //合併
{
    x  =  findr(x);
    y  =  findr(y);
     if (x  == y)
         return;
     par[x]  = y;
}
bool  same( int  xint  y) //判斷根是否相同
{
     return  findr(x)  ==  findr(y);
}
int  kruskal( int  Vint  E) //kruskal算法求最小生成樹
{
     sort(es, es  + E, cmp);
     init(V);
     int res  =  0;
     for ( int i  =  0; i  < E; i ++)
    {
        edge e  =  es[i];
         if ( ! same( e. ue. v))
        {
             unite( e. ue. v);
            res  +=  e. cost;
        }
    }
     return res;
}
int  main()
{
     int T;
     scanf( " %d "&T);
     while (T --) //T組測試樣例
    {
         scanf( " %d%d%d "&N,  &M,  &R); //存數據
         for ( int i  =  0; i  < R; i ++)
             scanf( " %d%d%d "& x[i],  & y[i],  & d[i]);
         int V, E;
        V  = N  + M; //頂點個數
        E  = R; //邊個數
         for ( int i  =  0; i  < E; i ++) //存入結構體
        {
             es[i]  = (edge){
                 x[i], N  +  y[i],  - d[i]};
        }
         printf( " %d \n "10000  * (N  + M)  +  kruskal(V, E));
    }
     return  0;
}
相關文章
相關標籤/搜索