UVALive 2531 The K-League(最大流、公平分配模型)

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=532

题目大意:有n个队伍进行比赛,每场比赛,恰好有一支队伍取胜、一支队伍败。每个队伍需要打的比赛场数相同,给你每个队伍目前已经赢得场数和输得场数,再给你一个矩阵,第 i 行第 j 列 表示队伍 i 和队伍 j 还需要打的比赛数,问你哪些队伍有可能获得冠军(胜场最多的即为冠军,可以并列)。

解题思路:由于队伍数很少,可以想到枚举。那么对于队伍 i 怎么知道他可不可以获得冠军,首先,矩阵中它的比赛肯定是全都赢,这样就能得到它最多的胜场数,然后再判断这个时候,其他队伍胜场会不会都不超过它。那么关键就在于这里如何判断了。

        每场比赛只有 u 胜或者 v 胜这两个可能性,把每场比赛看做一个任务,每支队伍看做一个处理器,得到一个“公平分配模型”。

        何为“公平分配模型”?即把 m 任务分配给 n 个处理器,每个任务有两个处理器可以选择,这两个处理器保证不相同,可以任选一个分配,要求任务数最多的那个处理器分配的任务最小。

        怎么解?这是一个二分图模型,X 表示任务, Y 表示处理器。二分答案 x ,表示这个最多的任务数。从 S 出发引一条边到所有的任务,cap 为 1 。然后从每个任务引两条边分别到对应的两个处理器,cap 为 1。然后再从所有处理器引一条边打 T,cap 为 x 。如果总流量为 m ,那么所有任务都分配掉了,方案可行。

        对于这道题,既然这样一个模型抽象出来了,那么就是一样,每两支队伍的比赛是一个 X 节点,每支队伍是一个 Y 节点。从 S 出发引 cap = a[ i ][ j ] 的边到这个 X 节点,a[ i ][ j ] 为 队伍 i 和队伍 j 剩下的比赛数。再从每个 X 节点,引两条边到对应的队伍,cap  = INF 。再从每个队伍(Y节点)引一条边到 T,cap = total[ x ] - win[ k ] ,x 为当前枚举的队伍,win[ k ] 为队伍 k 已经赢得的比赛数。判断能不能行,就只要看从 S 出发的每条边是不是都满载了,或者看总流量也可以。另外建边的时候,上面到 T 的边的 cap 如果 < 0,即total[ x ] < win[ k ],那么就是不可能,人家已经赢得比赛都比你多了,直接不可能,要不然这个 cap 就是 负的了。

      网络流的题目都是神建模啊!ORZ

代码如下:

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;

const int INF = 0x0fffffff;
const int MAXN = 33*33*2+33;
const int MAXM = MAXN*MAXN*2;

int w[33],d[33],p[33][33],total[33];

struct Edge
{
    int s,t,cap,flow,next;
} edge[MAXM];

int head[MAXN],tot;

void edge_init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int s,int t,int cap)
{
    edge[tot].s = s;
    edge[tot].t = t;
    edge[tot].cap = cap;
    edge[tot].flow = 0;
    edge[tot].next = head[s];
    head[s] = tot++;

    edge[tot].s = t;
    edge[tot].t = s;
    edge[tot].cap = 0;
    edge[tot].flow = 0;
    edge[tot].next = head[t];
    head[t] = tot++;
}

struct Isap
{
    int n;
    int s,t;
    int hh[MAXN];
    int dis[MAXN],num[MAXN],pre[MAXN];
    bool vis[MAXN];

    void init(int n)
    {
        this->n = n;
    }

    int bfs()
    {
        queue<int> q;
        memset(vis,0,sizeof(vis));
        vis[t] = 1;
        q.push(t);
        dis[t] = 0;
        while(!q.empty())
        {
            int x = q.front();
            q.pop();
            for(int i = head[x];i != -1;i = edge[i].next)
            {
                Edge& e = edge[i^1];
                int to = e.s;
                if(!vis[to] && e.cap > e.flow)
                {
                    vis[to] = 1;
                    dis[to] = dis[x]+1;
                    q.push(to);
                }
            }
        }
        return vis[s];
    }

    int augment()
    {
        int x = t,a = INF;
        while(x != s)
        {
            a = min(a,edge[pre[x]].cap-edge[pre[x]].flow);
            x = edge[pre[x]].s;
        }
        x = t;
        while(x != s)
        {
            edge[pre[x]].flow += a;
            edge[pre[x]^1].flow -= a;
            x = edge[pre[x]].s;
        }
        return a;
    }

    int max_flow(int s,int t,int limit)
    {
        this->s = s;this->t = t;
        bfs();
        memset(num,0,sizeof(num));
        for(int i = 0;i < n;i++) num[dis[i]]++;
        for(int i = 0;i < n;i++) hh[i] = head[i];
        int x = s;
        int flow = 0;
        while(dis[s] < n)
        {
            if(x == t)
            {
                flow += augment();
                if(flow >= limit) break;
                x = s;
            }
            int ok = 0;
            for(int i = hh[x];i != -1;i = edge[i].next)
            {
                Edge& e = edge[i];
                int to = e.t;
                if(dis[x] == dis[to]+1 && e.cap > e.flow)
                {
                    ok = 1;
                    hh[x] = i;
                    pre[to] = i;
                    x = to;
                    break;
                }
            }
            if(!ok)
            {
                int m = n-1;
                for(int i = head[x];i != -1;i = edge[i].next)
                {
                    Edge& e = edge[i];
                    int to = e.t;
                    if(e.cap > e.flow)
                        m = min(m,dis[to]);
                }
                if(--num[dis[x]] == 0) break;
                num[dis[x] = m+1]++;
                hh[x] = head[x];
                if(x != s) x = edge[pre[x]].s;
            }
        }
        return flow;
    }
} sol;

int id_s,id_tt,id[MAXN][MAXN],cc;

int get_id(int i,int j)
{
    if(j == -1) return cc+i;
    else return id[i][j];
}

int build(int x,int n)
{
    for(int i = 0;i < n;i++)
        for(int j = i+1;j < n;j++)
        {
            int id = get_id(i,j);
            add_edge(id_s,id,p[i][j]);

            add_edge(id,get_id(i,-1),INF);

            add_edge(id,get_id(j,-1),INF);
        }
    for(int i = 0;i < n;i++)
    {
        if(total[x] < w[i])
        {
            return 0;
        }
        add_edge(get_id(i,-1),id_tt,total[x]-w[i]);
    }
    return 1;
}

int check()
{
    int ok = 1;
    for(int i = head[id_s];i != -1;i = edge[i].next)
    {
        Edge& e = edge[i];
        if(e.cap != e.flow)
        {
            ok = 0;
            break;
        }
    }
    return ok;
}

int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 0;i < n;i++)
            scanf("%d%d",&w[i],&d[i]);
        cc = 0;
        for(int i = 0;i < n;i++)
        {
            total[i] = w[i];
            for(int j = 0;j < n;j++)
            {
                scanf("%d",&p[i][j]);
                total[i] += p[i][j];
            }
        }
        for(int i = 0;i < n;i++)
            for(int j = i+1;j < n;j++)
                id[i][j] = cc++;
        cc++;
        id_s = cc+n,id_tt = id_s+1;
        sol.init(id_tt+1);
        int first = 1;
        for(int i = 0;i < n;i++)
        {
            edge_init();
            int flag = build(i,n);
            if(!flag) continue;
            sol.max_flow(id_s,id_tt,INF);
            if(check())
            {
                if(first)
                {
                    printf("%d",i+1);
                    first = 0;
                }
                else printf(" %d",i+1);
            }
        }
        puts("");
    }
    return 0;
}

/*
11
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

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 league/flysystem-sftp-v3 插件需要先安装并配置好 Flysystem。Flysystem 是一个基于 PHP 的文件系统抽象层,它提供了一组通用的 API,可以让你轻松地处理本地和远程文件系统。你可以通过 Composer 安装 Flysystem: ``` composer require league/flysystem ``` 然后,你需要安装 league/flysystem-sftp-v3 插件: ``` composer require league/flysystem-sftp-v3 ``` 安装完成后,你可以使用以下代码示例来连接 SFTP 服务器并进行文件操作: ```php use League\Flysystem\Filesystem; use League\Flysystem\Sftp\SftpAdapter; // 配置 SFTP 服务器连接参数 $config = [ 'host' => 'example.com', 'port' => 22, 'username' => 'username', 'password' => 'password', 'root' => '/path/to/remote/root', ]; // 创建 SFTP 适配器 $adapter = new SftpAdapter($config); // 创建 Flysystem 文件系统 $filesystem = new Filesystem($adapter); // 在远程服务器创建一个目录 $filesystem->createDir('remote/path/to/directory'); // 上传一个本地文件到远程服务器 $contents = file_get_contents('/path/to/local/file'); $filesystem->write('remote/path/to/file', $contents); // 下载远程服务器的一个文件到本地 $contents = $filesystem->read('remote/path/to/file'); file_put_contents('/path/to/local/file', $contents); // 删除远程服务器上的一个文件 $filesystem->delete('remote/path/to/file'); ``` 你可以根据具体的需求,使用其他方法来进行文件操作。更详细的使用说明可以参考 Flysystem 和 league/flysystem-sftp-v3 的官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值