程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> SGU 210 Acdream 1227 Beloved Sons KM

SGU 210 Acdream 1227 Beloved Sons KM

編輯:C++入門知識

SGU 210 Acdream 1227 Beloved Sons KM


題目鏈接:點擊打開鏈接

題意:

給定n個人

每個人的點權

下面n行i行表示第i個人可以獲得哪些數(數字從1-n,且不能重復分配)

若這個人獲得了數字則你可以獲得他的權值。

要你能獲得的權值和最大。

問:

輸出每個人應該獲得哪個數字,若沒有獲得到數字則輸出0.


思路:

KM,每個人給每個數字連一條邊,邊權是這個人的權值,

對於這個人不能獲得的數字連一條邊權為0的邊。


#include 
#include 
#define M 410
#define inf 0x3f3f3f3f
 
int n,nx,ny;
int link[M],lx[M],ly[M],slack[M], linkx[M];    //lx,ly為頂標,nx,ny分別為x點集y點集的個數
int visx[M],visy[M],w[M][M];
 
int DFS(int x)
{
    visx[x] = 1;
    for (int y = 1;y <= ny;y ++)
    {
        if (visy[y])
            continue;
        int t = lx[x] + ly[y] - w[x][y];
        if (t == 0)       //
        {
            visy[y] = 1;
            if (link[y] == -1||DFS(link[y]))
            {
                link[y] = x;
                linkx[x] = y;
                return 1;
            }
        }
        else if (slack[y] > t)  //不在相等子圖中slack 取最小的
            slack[y] = t;
    }
    return 0;
}
int KM()
{
    int i,j;
    memset (link,-1,sizeof(link));
    memset (ly,0,sizeof(ly));
    for (i = 1;i <= nx;i ++)            //lx初始化為與它關聯邊中最大的
        for (j = 1,lx[i] = -inf;j <= ny;j ++)
            if (w[i][j] > lx[i])
                lx[i] = w[i][j];
 
    for (int x = 1;x <= nx;x ++)
    {
        for (i = 1;i <= ny;i ++)
            slack[i] = inf;
        while (1)
        {
            memset (visx,0,sizeof(visx));
            memset (visy,0,sizeof(visy));
            if (DFS(x))     //若成功(找到了增廣軌),則該點增廣完成,進入下一個點的增廣
                break;  //若失敗(沒有找到增廣軌),則需要改變一些點的標號,使得圖中可行邊的數量增加。
                        //方法為:將所有在增廣軌中(就是在增廣過程中遍歷到)的X方點的標號全部減去一個常數d,
                        //所有在增廣軌中的Y方點的標號全部加上一個常數d
            int d = inf;
            for (i = 1;i <= ny;i ++)
                if (!visy[i]&&d > slack[i])
                    d = slack[i];
            for (i = 1;i <= nx;i ++)
                if (visx[i])
                    lx[i] -= d;
            for (i = 1;i <= ny;i ++)  //修改頂標後,要把所有不在交錯樹中的Y頂點的slack值都減去d
                if (visy[i])
                    ly[i] += d;
                else
                    slack[i] -= d;
        }
    }
    int res = 0;
    for (i = 1;i <= ny;i ++)
        if (link[i] > -1)
            res += w[link[i]][i];
    return res;
}
 
template 
inline bool rd(T &ret) {
    char c; int sgn;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
template 
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
using namespace std;
int a[401];
void build(){
    for(int i = 1; i <= n; i++)
        rd(a[i]), a[i] = a[i]*a[i];
    for(int i = 1, siz, u; i <= n; i++)
    {
        memset(w[i], 0, sizeof w[i]);
        rd(siz);
        while(siz--) {
            rd(u);
            w[i][u] = a[i];
        }
    }
    nx = ny = n;
    KM();
}
int main(){
    while(rd(n)){
        build();
        for(int i = 1; i <= n; i++) {
            if(w[i][linkx[i]])
                pt(linkx[i]);
            else putchar('0');
            i == n?puts("") : putchar(' ');
        }
    }
    return 0;
}


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved