[COGS2653]源符「厌川的翡翠」-网络流

本题描述了一个关于仙人掌图的问题,需要在图的每个节点上分配一个数值,使得相邻节点间的数值差不超过特定值,同时保证所有节点的不稳定系数之和不超过给定值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源符「厌川的翡翠」

题目更新:

现在第13,14,15,16组数据满足m=n-1
所有整数都是正整数
第7,8,9,10,11,12组数据的范围更改为:n,t<=40, m<=50
已添加一句话题意
已将样例2更换为更强的样例

请不要在代码或评论中添加任何可能引起时间以为单位变化的内容

【题目描述】

诹访子和神奈子需要合力帮助早苗!
早苗作为神社的风祝,有时也需要解决异变,但在一次异变中早苗遇到了非常强大的敌人,需要诹访子和神奈子的援助。诹访子打算使用符卡”源符「厌川的翡翠」”来帮助早苗,同时神奈子会使用藤蔓来增加诹访子符卡的威力。
符卡”源符「厌川的翡翠」”会放出n个翡翠,神奈子则会操纵m条藤蔓连接这些翡翠,一些翡翠可能会被藤蔓连接成一个环,但是没有两个翡翠连成的环中有相同的藤蔓,所有的翡翠都能通过藤蔓连接到其它翡翠。在战斗中诹访子可以任意将翡翠的硬度调节为[1,t]中的整数,如果第i个翡翠的硬度为j,则整个符卡会获得v[i][j]的不稳定系数,而且符卡的威力和用藤蔓连接的两个翡翠硬度的差值有关。
由于诹访子并不擅长数学,早苗又要与敌人交战,所以她请你来帮她找到一个最小的整数c,满足存在一种给翡翠设置硬度的方案,使得没有两个被藤蔓连接的翡翠硬度的差值大于c且所有翡翠的不稳定系数之和不大于w。

一句话题意:
给个仙人掌,仙人掌上每个点都能填入[1,t]中的整数,第i个点填j会获得收益v[i][j],求一个最小的c,使得存在一种填数的方案,满足没有两个用边相邻的点填的数差值超过c且所有点的收益和不超过w

【输入格式】

第一行四个整数n,m,w,t,意义如上
接下来m行,每行三个整数l和r,表示第l个铁轮和第r个翡翠用藤蔓连接在一起
接下来一个n行t列的整数矩阵,第i行第j列的数表示第i个翡翠硬度为j所获得的不稳定系数

【输出格式】

如果敌人太强了诹访子和神奈子联手都无法战胜,输出-1
否则一行一个整数c,意义如上

【样例输入1】

5 5 5 2
1 2
1 4
3 4
4 5
3 5
1 2
2 1
1 2
2 1
1 2

【样例输出1】

1

【样例输入2】

10 11 20 10
1 2
1 3
3 4
2 5
3 6
6 7
3 8
1 9
1 10
1 8
1 5
7 2 3 9 9 10 10 4 4 7
1 7 1 9 3 1 1 2 4 6
1 2 10 3 5 10 3 5 5 4
1 9 3 8 4 4 2 2 3 2
2 4 1 10 7 7 8 3 8 7
9 3 8 3 2 10 7 3 10 1
3 3 7 7 4 9 3 7 10 5
9 5 8 7 1 3 2 10 5 8
9 10 10 10 4 6 2 9 4 9
7 10 8 10 2 1 4 3 9 10

【样例输出2】

3

【数据范围】

n,t<=150,m<=200,w<=100000,v<=5000000

【ex】

还有诹访子和神奈子联合起来都打不过的人(妖怪/神……)?
正邪啊,谁自机谁最强seija1

吓得我都去玩 弹幕天邪鬼 了↓↓↓
seija2


《论根据名字选择题目的优越性2》
这题就是咱去做切糕的原因……


思路:
可以先去看看切糕
(这是一道题的名字不要误会)
看完想必就不需要往下看了,可以直接做出这道题了……

好吧其实还是有一点点区别的……
咱考虑二分这个答案c,使用网络流判断。
然后判定方法嘛……瞬间变成了切糕是不是呀……

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

inline int read()
{
    int x=0;char ch=getchar();
    while(ch<'0' || '9'<ch)ch=getchar();
    while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
    return x;
}

typedef pair<int,int> pr;
const int NN=159;
const int Inf=1e9;

int n,m,w,d;
vector<pr> wea;
int v[NN][NN];

const int N=1e5+9;
const int M=1e6+9;

inline int po(int u,int d)
{
    return u+(d-1)*n;
}

int to[M],nxt[M],cap[M],beg[N],tot;
int s,t,dis[N],q[N];

inline void adde(int u,int v,int c)
{
    to[++tot]=v;
    nxt[tot]=beg[u];
    cap[tot]=c;
    beg[u]=tot;
}

inline void add(int u,int v,int c)
{
    adde(u,v,c);
    adde(v,u,0);
}

inline bool bfs()
{
    int l=0,r=1;
    memset(dis,0,sizeof(dis));
    q[1]=s;
    dis[s]=1;

    while(l<r)
    {
        int u=q[++l];
        for(int i=beg[u],v;i;i=nxt[i])
            if(!dis[v=to[i]] && cap[i])
            {
                dis[v]=dis[u]+1;
                q[++r]=v;
            }
    }
    return dis[t];
}

inline int dfs(int u,int mflow)
{
    if(u==t || !mflow)
        return mflow;
    int cost=0;
    for(int i=beg[u],v,f;i;i=nxt[i])
        if(dis[v=to[i]]==dis[u]+1 && cap[i])
        {
            f=dfs(v,min(mflow-cost,cap[i]));
            cap[i]-=f;
            cap[i^1]+=f;
            cost+=f;
            if(mflow==cost)
                break;
        }
    if(!cost)
        dis[u]=-1;
    return cost;
}

inline int dinic()
{
    int ret=0;
    while(bfs())
        ret+=dfs(s,Inf);
    return ret;
}

inline void init()
{
    memset(nxt,0,sizeof(nxt));
    memset(beg,0,sizeof(beg));
    tot=1;
}

inline bool judge(int c)
{
    init();
    for(int j=1;j<=n;j++)
    {
        add(s,po(j,1),Inf);
        add(po(j,d),t,v[j][d]);
        for(int i=1;i<d;i++)
            add(po(j,i),po(j,i+1),v[j][i]);
    }
    for(int i=0,e=wea.size();i<e;i++)
        for(int j=1+c;j<=d;j++)
        {
            add(po(wea[i].first,j),po(wea[i].second,j-c),Inf);
            add(po(wea[i].second,j),po(wea[i].first,j-c),Inf);
        }
    return dinic()<=w;
}

int main()
{
    freopen("cdcq_c.in","r",stdin);
    freopen("cdcq_c.out","w",stdout);

    n=read();m=read();
    w=read();d=read();
    s=n*d+1;t=s+1;
    for(int i=1;i<=m;i++)
        wea.push_back((pr){read(),read()});
    for(int i=1;i<=n;i++)
        for(int j=1;j<=d;j++)
            v[i][j]=read();

    int l=0,r=d+1,mid,ans=-1;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(judge(mid))
            ans=mid,r=mid-1;
        else
            l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值