uva 1306 The K-League (最大流)

uva 1306 The K-League

Description

Supporters for the professional soccer clubs participating in the K-League, formerly the Korea Professional Soccer League, hold orderly and organized cheering, as did the Red Devils, the official supporters for the Korean national soccer team during the 2002 Korea-Japan World Cup. After many games of this season have been played, the supporters may wonder whether the team S they are backing can still win the championship. In other words, can winners be assigned for the remaining games so that no team ends with more victories than S?(Two or more teams can win the championship jointly.)

You are given the current number of wins and defeats, wi and di, for every team i, 1<=i<=n, and the remaining number, ai,j, of games to be played between every pair of teams i and j, 1<=i,j<=n, where n is the number of teams. The teams are numbered 1,2,…,n. You are to find all teams that have a possibility of winning the championship. Every team has to play the same number games during the season. For simplicity, we assume that there are no draws, that is, every game has a winner and a loser.

Input

The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case consists of three lines: the first line has an integer n, 1<=n<=25, that represents the number of teams in the test case; the second line contains 2n nonnegative integers w1,d1,w2,d2… each at most 100, where wi and di are the current numbers of wins and defeats for team i, respectively; the third line contains n2 nonnegative integers a1,1,a1,2,… each at most 10, where ai,j is the remaining number of games to be played between teams i and j . For all i and j, ai,j=aj,i. If i=j, then ai,j=0. The integers given in a line are delimited by one or more spaces.

Output

Print exactly one line for each test case. The line should contain all teams that have a possibility of winning the championship, in an increasing order of team numbers.

Sample Input

3

3

2 0 1 1 0 2

0 2 2

2 0 2

2 2 0

3

4 0 2 2 0 4

0 1 1

1 0 1

1 1 0

4

0 3 3 1 1 3 3 0

0 0 0 2

0 0 1 0

0 1 0 0

2 0 0 0

Sample Output

1 2 3

1 2

2 4

题目大意:有n支球队进行比赛,每只队伍需要打的比赛数目相同。每场比赛恰好一支队伍胜,另一支败。给出每支队伍目前胜的场数和败的场数,以及每两个队伍还剩下的比赛场数,确定所有可能的冠军的球队(获胜常数最多的的冠军,可以并列)。

解题思路:要分成n次来判断。对于当前队伍,使它在接下来的比赛中全部获胜,则它的获胜总场次为total。设置超级源点,连向每两队之间的比赛,容量为这两队之间还剩下的比赛场次。设置超级汇点,使所有队伍连向它,容量为total减去这支队伍已获胜的场次win[i]。然后每两队之间的比赛,连向这两只队伍,容量为INF。跑最大流,若连向超级源点的边能满流,则当前队伍有可能获得冠军。total - win[i]代表这支队伍在接下来的比赛中,胜利总场次不能超过当前队伍最多的胜利场次total。如果total - win[i] < 0或者连向超级源点的边没有满流,说明,其他队伍再怎么放水,这支队伍也得不到冠军。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <cctype>
using namespace std;

typedef long long ll;
const int PO = 30;
const int N = 1000;
const int M = 20000;
const int INF = 0x3f3f3f3f;
int n, F[PO][PO], s, t;
struct Node{
    int w, l;
}team[PO];

namespace IO {
    const static int maxn = 20 << 20;
    static char buf[maxn], *pbuf = buf, *End;
    void init() {
        int c = fread(buf, 1, maxn, stdin);
        End = buf + c;
    }
    int &readint() {
        static int ans;
        ans = 0;
        while (pbuf != End && !isdigit(*pbuf)) pbuf ++;
        while (pbuf != End && isdigit(*pbuf)) {
            ans = ans * 10 + *pbuf - ‘0‘;
            pbuf ++;
        }
        return ans;
    }
}

struct Edge{
    int from, to;
    int cap, flow;
};

struct Dinic{
    vector<Edge> edges;
    vector<int> G[M];
    int vis[N], d[N];
    int cur[M];
    int ans;

    void init() {
        ans = 0;
        for (int i = 0; i < M; i++) G[i].clear();
        edges.clear();
    }

    void addEdge(int from, int to, int cap) {
        edges.push_back((Edge){from, to, cap, 0});
        edges.push_back((Edge){to, from, 0, 0});
        int m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    } 

    int BFS() {
        memset(vis, 0, sizeof(vis));
        queue<int> Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            for (int i = 0; i < G[u].size(); i++) {
                Edge &e = edges[G[u][i]];
                if (!vis[e.to] && e.cap > e.flow) {
                    vis[e.to] = 1;
                    d[e.to] = d[u] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int u, int a) {
        if (u == t || a == 0) return a;
        int flow = 0, f;
        for (int &i = cur[u]; i < G[u].size(); i++) {
            Edge &e = edges[G[u][i]];
            if (d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
                e.flow += f;
                edges[G[u][i]^1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }

    int dinic() {
        while (BFS()) {
            memset(cur, 0, sizeof(cur));
            ans += DFS(s, INF);
        }
        return ans;
    }
}din;

void input() {
    n = IO::readint();
    s = 0, t = n * (n + 1) + 2;
    for (int i = 1; i <= n; i++) {
        team[i].w = IO::readint();
        team[i].l = IO::readint();
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            F[i][j] = IO::readint();
        }
    }
}

int getTotal(int x) {
    int sum = team[x].w;
    for (int i = 1; i <= n; i++) {
        sum += F[x][i];
    }
    return sum;
} 

void solve() {
    for (int i = 1; i <= n; i++) {
        din.addEdge(i, t, 0);
    }
    int cnt = 1, rec = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            din.addEdge(s, cnt + n, F[i][j]);
            rec += F[i][j];
            din.addEdge(cnt + n, i, INF);
            din.addEdge(cnt + n, j, INF);
            cnt++;
        }
    }
    int flag = 0;
    for (int i = 1; i <= n; i++) {
        int tot = getTotal(i), cap;
        for (int j = 0; j < din.edges.size(); j++) din.edges[j].flow = 0;
        for (int j = 0; j < 2 * n; j += 2) {
            cap = tot - team[(j / 2) + 1].w;
            if (cap < 0) {
                cap = -1;
                break;
            }
            din.edges[j].cap = cap;
        }
        if (cap == -1) continue;
        din.ans = 0;
        if (din.dinic() == rec) {
            if (flag) printf(" ");
            printf("%d", i);
            flag = 1;
        }
    }puts("");
}

int main() {
    IO::init();
    int T;
    T = IO::readint();
    while (T--) {
        din.init();
        input();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不可转载。

时间: 2024-10-10 08:12:37

uva 1306 The K-League (最大流)的相关文章

UVA 1306 - The K-League(网络流)

UVA 1306 - The K-League 题目链接 题意:n个球队,已经有一些胜负场,现在还有一些场次,你去分配胜负,问每支球队有没有可能获胜 思路:网络流公平分配模型,把场次当作任务,分配给人,然后先贪心,枚举每个人,让这些人能赢的都赢,剩下的去建图,每个源点连向比赛容量为场次,每个比赛连向2个球队,容量无限大,每个球队连向汇点,容量为每个的人的总和减去当前已经赢的,建完图跑一下最大流,然后判断源点流出的是否都满流即可 代码: #include <cstdio> #include &l

UVA 11997 The K smallest Sums

给出K*K的矩阵,每一行取一个数,构成K个数的和,总共有 k^k种可能,从中取出前k个最小的. 一开始犯了错,因为只要对每行排序,最小的必定是第一列的和,然后我当时就想着,逐步推进,每次将某行的那个数变成其下一列那个数,当然间距要最小.我这样明显是不对的,这样的话每个数只用了一次,而题目的意思明显是可以重复多次. 然后大白上说的是把他看成两行,即每次处理两行,留下最小的k个 再与下一次读入的那一行继续处理.这个方法相当给力,不过有个难点是,怎么在两行的时候,比较快的得到前k小的,我试过全部算一遍

UVA 10330 Power Transmission(网络最大流)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1271  Power Transmission  The Problem DESA is taking a new project to transfer power. Power is generated by the newly established plant in Barisal.

uva 11248 Frequency Hopping (最大流)

uva 11248 Frequency Hopping 题目大意:给定一个有向网络,每条边均有一个容量. 问是否存在一个从点1到点N.流量为C的流.假设不存在,能否够恰好改动一条弧的容量,使得存在这种流. 解题思路:先依照题目给出的边建好图,然后跑一发最大流,得到原始最大流C1,假设C1==C或者C==0时.能够直接输出possible.假设不存在这种流.那么開始找割边,将这些割边的容量添加C,再求最大流.假设能够,那么要输出全部的方案.改动全部割边后,仍没有符合条件的流,输出 not poss

uva 1161 Objective: Berlin (最大流)

uva 1161 Objective: Berlin 题目大意:你要从A地到B地去,并且最晚要在lt之前到达.现在给你m个航班信息,信息包括:起始地点,降落地点,载客上限,起飞时间,降落时间.中途转机要花费半小时的时间.问在lt之前,可以从A地到达B地的最多的游客数量. 解题思路:以航班为节点进行建图.设置超级源点,连向所有起点为A地的航班,容量为INF:设置超级汇点,使所有降落地点为B点且降落时间在lt之前的航班连向超级汇点.每个航班都要拆成两个节点,中间的边容量为该航班的载客上限.如果i航班

uva 10330 Power Transmission (最大流 + 拆点)

uva 10330 Power Transmission 如果对最大流不熟悉的话可以先去看看这个 题目大意:先来讲解一下INPUT.首先读入一个正整数N, 接下来N个数据是N个调节器的容量:然后读入一个正整数M, 接下来M组数据代表的是M条调节器与调解器之间的线路(调节器u, 调节器v, 容量);最后的一组数据先是两个正整数a和b, 接下来的a个数据代表的是初始的调节器,最后的b个数据代表的是终结的调节器. 综上,求最大流. 解题思路:源点或汇点不唯一的时候,记得要增加超级源点或超级汇点来使得源

UVA, 11380Down Went The Titanic(最大流,拆点)

最大流,拆点 题意:@可以无限走,*人的初始位置,其他人不能走.~水,不能走, ...只能走一次,#终点,可以容纳的人数为p:问最多有多少人获救(到达了#) 这道题是最大流问题,主要是要去构建图.怎么构建图呢?主要是用拆点,把一个点拆成两个点,点(i,j)可以表示为:前点(i-1)*A+j,后点(i-1)*A+j+M(M为一个较大的数,保证M大于等于S*A就行),然后连接前点和后点,方向是从前点到后点,@和#他们的前点和后点边的权值设置无穷大. 相邻的点,图是无向的,用该点的后点连接相邻点的前点

UVa 11082 - Matrix Decompressing(最大流)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2023 题意: 对于一个R行C列的正整数矩阵(1≤R,C≤20),设Ai为前i行所有元素之和,Bi为前i列所有元素之和.已知R,C和数组A和B,找一个满足条件的矩阵.矩阵中的元素必须是1-20之间的正整数.输入保证有解. 分析: 首先根据Ai和Bi计算出第i行的元素之和Ai'和第i列

uva 1658 Admiral 最小费最大流

题意就是让你求两次1到n的最短路.这题应该可以用最短路来求解吧,只需要将第一次用到的边删去即可.我这里是按照算法竞赛入门经典里面提到拆点+最小费最大流. #include<bits/stdc++.h> using namespace std; const int N=1024*4; const int inf=1<<24; struct Edge { int from,to,cap,flow,cost; }; vector<Edge>edges; vector<i