1. 程式人生 > >Conscription(POJ 3723)

Conscription(POJ 3723)

矛盾 The true 求解 have const fine i++ when

  • 原題如下: Conscription
    Time Limit: 1000MS Memory Limit: 65536K
    Total Submissions: 16584 Accepted: 5764

    Description

    Windy has a country, and he wants to build an army to protect his country. He has picked up N girls and M boys and wants to collect them to be his soldiers. To collect a soldier without any privilege, he must pay 10000 RMB. There are some relationships between girls and boys and Windy can use these relationships to reduce his cost. If girl x

    and boy y have a relationship d and one of them has been collected, Windy can collect the other one with 10000-d RMB. Now given all the relationships between girls and boys, your assignment is to find the least amount of money Windy has to pay. Notice that only one relationship can be used when collecting one soldier.

    Input

    The first line of input is the number of test case.
    The first line of each test case contains three integers, N, M and R.
    Then R lines followed, each contains three integers xi, yi and di.
    There is a blank line before each test case.

    1 ≤ N, M ≤ 10000
    0 ≤ R ≤ 50,000
    0 ≤ xi < N
    0 ≤ yi < M
    0 < di < 10000

    Output

    For each test case output the answer in a single line.

    Sample Input

    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 781
    
    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 3133
    

    Sample Output

    71071
    54223
  • 題解:設想這樣一個無向圖:在征募某個人a時,如果使用了a和b之間的關系,那麽就連一條a到b的邊,假設這個圖中存在圈,那麽無論以什麽順序征募這個圈上的所有人,都會產生矛盾,即由於圈的存在,矛盾是必然的,由此可以知道,這個圖應該是一片森林。反過來,給定一片森林裏,必然可以使用對應的關系確定征募的順序。綜上,把人看作點,關系看作邊,這個問題就可以轉化為求解無向圖中的最大權森林問題,最大權森林問題可以通過把所有邊權取反後用最小生成樹的算法求解
  • 代碼:
      1 #include <cstdio>
      2 #include <queue>
      3 #include <vector>
      4 #include <algorithm>
      5 #include <cctype>
      6 #define num s-‘0‘
      7 
      8 using namespace std;
      9 
     10 struct edge
     11 {
     12     int u;
     13     int v;
     14     int cost;
     15 };
     16 
     17 const int MAX_V=30000;
     18 const int MAX_E=60000;
     19 const int INF=0x3f3f3f3f;
     20 int K,N, M, E, V;
     21 edge es[MAX_E];
     22 long long res;
     23 int par[MAX_V];
     24 int r[MAX_V];
     25 
     26 void kruskal();
     27 void init();
     28 int find(int);
     29 void unite(int, int);
     30 bool same(int, int);
     31 
     32 void read(int &x){
     33     char s;
     34     x=0;
     35     bool flag=0;
     36     while(!isdigit(s=getchar()))
     37         (s==-)&&(flag=true);
     38     for(x=num;isdigit(s=getchar());x=x*10+num);
     39     (flag)&&(x=-x);
     40 }
     41 
     42 void write(int x)
     43 {
     44     if(x<0)
     45     {
     46         putchar(-);
     47         x=-x;
     48     }
     49     if(x>9)
     50         write(x/10);
     51     putchar(x%10+0);
     52 }
     53 
     54 bool compare(const edge &e1, const edge &e2)
     55 {
     56     return e1.cost<e2.cost;
     57 }
     58 
     59 int main()
     60 {
     61     read(K);
     62     for (int j=0; j<K; j++)
     63     {
     64         res=0;
     65         read(N);read(M);read(E);V=N+M;
     66         for (int i=0; i<E; i++)
     67         {
     68             read(es[i].u);read(es[i].v);read(es[i].cost);
     69             es[i].v+=N;es[i].cost=-es[i].cost;
     70         }
     71         kruskal();
     72         write(10000*(N+M)+res);
     73         putchar(\n);
     74     }
     75 }
     76 
     77 void init()
     78 {
     79     for (int i=0; i<V; i++)
     80     {
     81         par[i]=i;
     82         r[i]=0;
     83     }
     84 }
     85 
     86 int find(int x)
     87 {
     88     if (par[x]==x) return x;
     89     return par[x]=find(par[x]);
     90 }
     91 
     92 void unite(int x, int y)
     93 {
     94     x=find(x);
     95     y=find(y);
     96     if (x==y) return;
     97     if (r[x]<r[y]) par[x]=y;
     98     else
     99     {
    100         par[y]=x;
    101         if (r[x]==r[y]) r[x]++; 
    102     } 
    103 }
    104 
    105 bool same(int x, int y)
    106 {
    107     return (find(x)==find(y));
    108 }
    109 
    110 void kruskal()
    111 {
    112     sort(es, es+E, compare);
    113     init();
    114     for (int i=0; i<E; i++)
    115     {
    116         edge e=es[i];
    117         if (!same(e.u, e.v))
    118         {
    119             unite(e.u, e.v);
    120             res+=e.cost;
    121         }
    122     }
    123 }

Conscription(POJ 3723)