首页 > 其他分享 >网络流与线性规划24题详解(上)

网络流与线性规划24题详解(上)

时间:2024-10-01 17:23:56浏览次数:1  
标签:24 cnt 线性规划 ed ll flow mxn int 详解

前言

题单
刷24题刷魔怔了,写个详解。
难度不断递增,T1-T9为蓝题,T10-T23为紫题。(什么?你问我为什么没有T24?)
好了,让我们开始吧!

T1 孤岛营救问题

思路:这题数据小,所以用BFS
\(key[x][y][k]\)记录\((x,y)\)的第k把钥匙
\(wall[x1][y1][x2][y2]\)记录墙和门
\(vis[x1][y1][k]\)记录是否走过\(x\)和\(y\),这里再多加一维存钥匙状态
关于钥匙,由于这题数据小\((\leq10)\),所以采用状压的思想存钥匙
注意:
1.同一格子可能有多把钥匙
2.一开始的\((1,1)\)也可能有钥匙,别忘了算进去
3.一把钥匙能用无数次
代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int wall[15][15][15][15];
int key[15][15][15],n,m,p,r,s,cnt[15][15];
int dir[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
bool vis[15][15][1<<15];
struct node{
    int x,y,step,k;
};
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m>>p>>r;
    for(int i=1;i<=r;i++)
    {
        int x1,y1,x2,y2,g;
        cin>>x1>>y1>>x2>>y2>>g;
        if(!g)wall[x1][y1][x2][y2]=-1,wall[x2][y2][x1][y1]=-1;
        else wall[x1][y1][x2][y2]=g,wall[x2][y2][x1][y1]=g; 
    }   
    cin>>s;
    for(int i=1;i<=s;i++)
    {
        int x1,y1,q;
        cin>>x1>>y1>>q;
        cnt[x1][y1]++;
        key[x1][y1][cnt[x1][y1]]=q;
    }
///////////////////////////bfs///////////////////////////
    queue<node> q;
    int sk=0;
    for(int i=1;i<=cnt[1][1];i++)
        sk|=1<<key[1][1][i];//状压 
    vis[1][1][sk]=1; 
    q.push((node){1,1,0,sk});
    while(!q.empty())
    {
        node u=q.front();
        q.pop();
        if(u.x==n&&u.y==m)
        {
            cout<<u.step;
            return 0;
        }
        for(int i=0;i<4;i++)
        {
            int vx=u.x+dir[i][0],vy=u.y+dir[i][1];
            int w=wall[u.x][u.y][vx][vy];
            if(vx<1||vy<1||vx>n||vy>m||w<0)continue;
            if(w&&((1<<w)&u.k)==0)continue;
            int vk=0;
            for(int i=1;i<=cnt[vx][vy];i++)
                vk|=1<<key[vx][vy][i];
            vk=u.k|vk;
            if(vis[vx][vy][vk])continue;
            q.push((node){vx,vy,u.step+1,vk}); 
            vis[vx][vy][vk]=1;
        }
    }
    cout<<-1;
    return 0;
} 

T2 飞行员配对方案问题

思路:二分图网络流
但这题确实是二分图裸模板,无脑套就行了。
代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,m,e,ans,match[510],match2[510];
bool vis[510],vis2[510];
vector<int> t[510];
bool dfs(int u){
	for(int i=0;i<t[u].size();i++){
		int v=t[u][i];
		if(!vis[v]){
			vis[v]=1;
			if(!match[v]||dfs(match[v])){
				match2[u]=v;
				match[v]=u;
				return 1;
			}
		}
	}
	return 0;
}
int main(){
	cin>>n>>m;
	while(1){
		int u,v;
		cin>>u>>v;
		if(u==-1&&v==-1)break;
		t[u].push_back(v);
	}
	for(int i=1;i<=n;i++){
		if(dfs(i))ans++,vis2[i]=1;
		memset(vis,0,sizeof(vis));
	}
	cout<<ans<<endl;
	for(int i=1;i<=n;i++)
		if(vis2[i])
			cout<<i<<' '<<match2[i]<<endl;
	return 0;
}

第二种做法是网络流,新加一个点把所有左边的点连起来,作为源点;新加一个点把所有右边的点连起来,作为汇点;每条边权值赋为\(1\)然后跑一遍最大流就行了。
注意输出匹配的时候判断汇点与右边点的反向边以及原点与左边点的反向边是否存在。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,t[110][110],dep[110],ans,st,ed;
ll pre[110];
void bfs(int s)
{
    dep[s]=1;
    queue<ll> q;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        for(int i=1;i<=n+1;i++)
        {
            if(dep[i]==0&&t[u][i]>0)
            {
                dep[i]=dep[u]+1;
                pre[i]=u;
                q.push(i);
            }
        }
    }
    return;
}
ll dfs(ll u,ll fl)
{
    if(u==ed)
        return fl;
    for(int i=1;i<=n+1;i++)
    {
        if(t[u][i]&&dep[i]==dep[u]+1)
        {
            ll d=dfs(i,min(fl,t[u][i]));
            if(d>0)
            {
                t[u][i]-=d;
                t[i][u]+=d;
                return d;
            }
        }
    }
    return 0;
}
ll dinic()
{
    while(1)
    {
        memset(dep,0,sizeof(dep));
        bfs(st);  
        if(!dep[ed])break;
        ll flg=1; 
        while(flg)
        {
            flg=dfs(st,1e18);
            if(flg)ans+=flg;
        }
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>m>>n;
    st=0,ed=n+1;
    int u,v;
    while(cin>>u>>v)
    {
        if(u==-1&&v==-1)break;
        t[u][v]=1;
    }
    for(int i=1;i<=m;i++)t[0][i]=1;
    for(int i=m+1;i<=n;i++)t[i][n+1]=1;
    cout<<dinic()<<'\n';
    for(int i=m+1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(t[n+1][i]&&t[j][0]&&t[i][j])
                cout<<j<<' '<<i<<'\n';
    return 0;
}

T3 软件补丁问题

思路:跑最短路
怎么跑?既然是最短路,就得有点(起点和终点)和边。本题\(n\)(错误总数)范围很小\((≤20)\),考虑状压,一开始全是错误,所以起点编号设为\(2^n-1\)(表示所有错误全都存在),最后错误全部消除,所以终点编号设为\(0\)。

判断当前状态\((u)\)是否包含\(b_1\),不包含\(b_2\),考虑用二进制的\(\&\)(与)符号,若\(u\&b_1==b_1\)则包含\(b_1\),若\(u\&b_2==0\)则不包含\(b_2\)。

要消除\(u\)中的\(f_1\),加上\(f_2\),考虑使用\(|\)(或)和^(异或)符号,先让\(v=u|(f_1|f_2)\),这时\(v\)肯定包含\(f_1\)和\(f_2\),再异或\(f_1\)(把\(f_1\)消掉)。

把状态\(u\)时使用补丁\(m_i\)后的结果设为\(v\),则\(u-v\)为一条边,\(t_i\)为边权。之后就可以愉快地跑最短路了。

代码如下:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mp make_pair
using namespace std;
struct bag{
    int t,b1,b2,f1,f2;
}b[110];
int n,m,dis[1<<20+1];
bool vis[1<<20+1];
void dij()//最短路
{
    memset(dis,0x7f,sizeof(dis));
    priority_queue<pii,vector<pii>,greater<pii>> q;
    q.push(mp(0,(1<<n)-1));
    dis[(1<<n)-1]=0;
    while(!q.empty())
    {
        int d=q.top().first,u=q.top().second;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=1;i<=m;i++)
        {
            if((u&b[i].b1)!=b[i].b1||(u&b[i].b2)!=0)
                continue;
            int v=(u|(b[i].f1|b[i].f2))^b[i].f1;
            dis[v]=min(dis[v],d+b[i].t);
            q.push(mp(dis[v],v));
        }
    }
    return;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>b[i].t;
        string s;
        cin>>s;
        for(int j=0;j<s.length();j++)
        {
            if(s[j]=='+')b[i].b1|=(1<<j);
            if(s[j]=='-')b[i].b2|=(1<<j);    
        }    
        cin>>s;
        for(int j=0;j<s.length();j++)
        {
            if(s[j]=='-')b[i].f1|=(1<<j);
            if(s[j]=='+')b[i].f2|=(1<<j);    
        }   
    } 
    dij();
    if(dis[0]==0x7f7f7f7f)cout<<0;
    else cout<<dis[0];
    return 0;
}

T4 负载平衡问题

思路:数学+贪心网络流
虽然是网络流题单里面的题但还是要提及一下贪心做法。
这题怎么看上去这么像均分纸牌?只不过加了个环形的条件。
我们设\(\bar x_a\)为\(a1,a2,\cdots,a_n\)的平均数,\(x_i\)表示为第\(i\)个人给左边的人的纸牌数,则\(ans=|x_1|+|x_2|+\cdots+|x_n|=\sum\limits_{i=1}^{n}x_i\)。
考虑用\(x_1\)来表示\(x_i\)。我们列出如下方程:

\[\left\{ \begin{aligned} \bar x_a=a_1-x_1+x_2\\ \bar x_a=a_2-x_2+x_3\\ \cdots\\ \bar x_a=a_{n-1}-x_{n-1}+x_{n} \end{aligned} \right. \]

代入消元,可得:\(x_i=x_1-(a_1+\cdots+a_{i-1}-(i-1)\bar x_a)\)

令\(c_i=\sum\limits_{j=1}^{i-1}-(i-1)\bar x_a\)

则有\(x_i=x_1-c_i\)

\(ans=|x_1-c_1|\)(\(i=1\)时,\(c_i=0\))\(+|x_1-c_2|+\cdots+|x_1-c_n|\)。

明显这就是一个普通的绝对值方程,取\(x_1\)为\(c_1\sim c_n\)中位数时\(ans\)最小
代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,x[110],a[110],xn,ans,x_1;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        a[i]+=a[i-1];
    }
    xn=a[n]/n;
    for(int i=1;i<=n;i++)x[i]=a[i-1]-(i-1)*xn;
    sort(x+1,x+n+1);
    x_1=x[(n+1)/2];
    for(int i=1;i<=n;i++)
        ans+=abs(x_1-x[i]);
    cout<<ans;
    return 0;
}

接下来我们再讲讲网络流做法。
将每个仓库库存量减去平均数。建一个超级源点连向库存量为正数的仓库,而库存量为负数的仓库连向超级汇点,
单位费用为\(0\),容量为库存量的绝对值。
当然,每个点也要向旁边连边,单位费用为\(1\)(即搬运量),容量设为无限大。然后跑一遍\(dinic\)就行了,最后答案为最小花费。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define mxn 1010
using namespace std;
ll n,m,ans,st,ed,vis[110],ansc;
ll pre[110],dis[110],cnt;
ll head[mxn],to[mxn],val[mxn],t[mxn],nxt[mxn],w;
ll x[110],sum,flow[mxn],use[mxn];
ll ansmx,ansmn;
void add_edge(ll u,ll v,ll w,ll c)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w,val[cnt]=c;
    head[u]=cnt;        
    return;
}
bool bfs(int s)
{
    for(int i=0;i<=n+1;i++)
        dis[i]=1e15,pre[i]=0,vis[i]=0;
    vis[s]=1,dis[s]=0,flow[s]=1e15;
    queue<ll> q;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=nxt[i])
        {   
            ll v=to[i];
            if(dis[v]>dis[u]+val[i]&&t[i])
            {
                dis[v]=dis[u]+val[i];
                flow[v]=min(t[i],flow[u]);
                pre[v]=u,use[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return pre[n+1]!=0;
}
pair<ll,ll> dinic()
{ 
    while(bfs(0))
    {
        ansmx+=flow[n+1];
        int u=n+1;
        ansmn+=flow[n+1]*dis[n+1];
        while(u)
        {
            t[use[u]]-=flow[n+1];
            t[use[u]^1]+=flow[n+1];
            u=pre[u];
        }
    }
    return make_pair(ansmx,ansmn);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>x[i];
        sum+=x[i];
    }
    cnt=1;
    sum/=n;
    for(int i=1;i<=n;i++)
        x[i]-=sum;
    for(int i=1;i<=n;i++)
    {
        if(x[i]>0)
        {
            add_edge(0,i,x[i],0);
            add_edge(i,0,0,0);
        }
        if(x[i]<0)
        {
            add_edge(i,n+1,-x[i],0);
            add_edge(n+1,i,0,0);
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(i!=1)
        {
            add_edge(i,i-1,1e15,1);
            add_edge(i-1,i,0,-1);
        }
        if(i!=n)
        {
            add_edge(i,i+1,1e15,1);
            add_edge(i+1,i,0,-1);
        }
    }  
    add_edge(1,n,1e15,1); 
    add_edge(n,1,0,-1);
    add_edge(n,1,1e15,1); 
    add_edge(1,n,0,-1); 
    pair<ll,ll> ansp=dinic();
    cout<<ansp.second;
    return 0;
}

T5 分配问题

思路:KM最小费用流
其实可以一眼看出是二分图最大权完美匹配,但是我不会这是网络流题单,我们用\(dinic\)做。
还是建一个超级源点,一个超级汇点,将每个人和每份工作连一条边,因为不能选多份工作,所以容量设为\(1\)就行了,而把单位费用设为效益。源点向每个人连一条边,容量,每份工作向汇点连一条边,容量为\(1\),费用为\(0\)。
要求最大费用,就把费用取负求最小费用流,最后再把答案取负就行了。
代码如下:

#include<bits/stdc++.h>
#define pil pair<long long,long long>
#define ll long long
#define mp make_pair
#define mxn 100010
#define mxm 1010
using namespace std;
ll n,m,ans,st,ed,vis[mxm],ansc;
ll pre[mxm],dis[mxm],cnt;
ll head[mxn],to[mxn],val[mxn],t[mxn],nxt[mxn],w;
ll sum,flow[mxn],use[mxn],c[mxm][mxm];
ll ansmx,ansmn;
void add_edge(ll u,ll v,ll w,ll c)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w,val[cnt]=c;
    head[u]=cnt;        
}
bool bfs(int s)
{
    for(int i=0;i<=n*2+1;i++)
        dis[i]=1e15,pre[i]=-1,vis[i]=0,flow[i]=1e15;
    vis[s]=1,dis[s]=0;
    queue<ll> q;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=nxt[i])
        {   
            ll v=to[i];
            if(dis[v]>dis[u]+val[i]&&t[i])
            {
                dis[v]=dis[u]+val[i];
                flow[v]=min(t[i],flow[u]);
                pre[v]=u,use[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return pre[ed]!=-1;
}
pil dinic()
{ 
    while(bfs(st))
    {
        int u=ed;
        ansmx+=flow[ed];
        ansmn+=flow[ed]*dis[ed];
        while(u)
        {
            t[use[u]]-=flow[ed];
            t[use[u]^1]+=flow[ed];
            u=pre[u];
        }
    }
    return make_pair(ansmx,ansmn);
}
void init()
{
    for(int i=0;i<=cnt;i++)
    {
        head[i]=to[i]=t[i]=nxt[i]=val[i]=0;
        flow[i]=use[i]=0;
    }
    cnt=1;
    ansmx=ansmn=0;
    return;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n;
    st=0,ed=n*2+1;
    cnt=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            cin>>w;
            c[i][j]=w;
            add_edge(i,j+n,1,w);
            add_edge(j+n,i,0,-w);
        }
    for(int i=1;i<=n;i++)
    {
        add_edge(st,i,1,0);
        add_edge(i,st,0,0);
        add_edge(i+n,ed,1,0);
        add_edge(ed,i+n,0,0);
    }
    pil ansp=dinic();
    cout<<ansp.second<<'\n';
    init();
    for(int i=1;i<=n;i++)   
        for(int j=1;j<=n;j++)
        {
            w=c[i][j];
            add_edge(i,j+n,1,-w);
            add_edge(j+n,i,0,w);
        }
    for(int i=1;i<=n;i++)
    {
        add_edge(st,i,1,0);
        add_edge(i,st,0,0);
        add_edge(i+n,ed,1,0);
        add_edge(ed,i+n,0,0);
    }
    ansp=dinic();
    cout<<-ansp.second; 
    return 0;
}

T6 运输问题

思路:费用流
与上题差不多,就是输入输出变了一下。
源点连向仓库,商店连向货物,容量为货物量/需要货物量,费用\(0\)。仓库与商店连边,容量无限大,费用题干已给出。然后跑\(dinic\)。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define mxn 100010
#define mxm 2010
#define pil pair<long long,long long>
using namespace std;
ll n,m,st,ed,vis[mxm];
ll pre[mxm],dis[mxm],cnt;
ll head[mxn],to[mxn],val[mxn],t[mxn],nxt[mxn],w;
ll flow[mxn],use[mxn],a[mxm],b[mxm],c[mxm][mxm];
ll ansmx,ansmn,ans[mxm];
void add_edge(ll u,ll v,ll w,ll c)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w,val[cnt]=c;
    head[u]=cnt;        
}
bool bfs(int s)
{
    for(int i=0;i<=n+m+1;i++)
        dis[i]=1e15,pre[i]=-1,vis[i]=0,flow[i]=1e15;
    vis[s]=1,dis[s]=0;
    queue<ll> q;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=nxt[i])
        {   
            ll v=to[i];
            if(dis[v]>dis[u]+val[i]&&t[i])
            {
                dis[v]=dis[u]+val[i];
                flow[v]=min(t[i],flow[u]);
                pre[v]=u,use[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return pre[ed]!=-1;
}
pil dinic()
{ 
    while(bfs(st))
    {
        int u=ed;
        ansmx+=flow[ed];
        ansmn+=flow[ed]*dis[ed];
        while(u)
        {
            t[use[u]]-=flow[ed];
            t[use[u]^1]+=flow[ed];
            ans[u]=pre[u];
            u=pre[u];
        }
    }
    return mp(ansmx,ansmn);
}
void init()
{
    for(int i=0;i<=cnt;i++)
    {
        head[i]=to[i]=t[i]=nxt[i]=val[i]=0;
        flow[i]=use[i]=0;
    }
    cnt=1;
    ansmx=ansmn=0;
    return;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    st=0,ed=n+m+1,cnt=1;
    for(int i=1;i<=n;i++)
    {
        ll k;
        cin>>k;
        a[i]=k;
        add_edge(0,i,k,0);
        add_edge(i,0,0,0);
    }
    for(int i=1;i<=m;i++)
    {
        ll k;
        cin>>k;
        b[i]=k;
        add_edge(n+i,ed,k,0);
        add_edge(ed,n+i,0,0);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            ll k;
            cin>>k;
            c[i][j]=k;
            add_edge(i,j+n,1e15,k);
            add_edge(j+n,i,0,-k);
        }
    pil ansp=dinic();
    cout<<ansp.second<<'\n';
    init();
    for(int i=1;i<=n;i++)
    {
        ll k;
        k=a[i];
        add_edge(0,i,k,0);
        add_edge(i,0,0,0);
    }
    for(int i=1;i<=m;i++)
    {
        ll k;
        k=b[i];
        add_edge(n+i,ed,k,0);
        add_edge(ed,n+i,0,0);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            ll k;
            k=c[i][j];
            add_edge(i,j+n,1e15,-k);
            add_edge(j+n,i,0,k);
        }
    ansp=dinic();
    cout<<-ansp.second; 
    return 0;
}

T7 圆桌问题

思路:最大流
这题也很简单,建超级源汇点,源点连向单位,餐桌流向汇点,容量为人数/餐桌可容纳人数。注意是最大流,不需要费用。每个单位向每个餐桌连边,由于同一个单位的人不在同一餐桌就餐,所以容量设为\(1\)就行了。
最后判断最大流与总人数是否相同,不相同则无解。输出方案时枚举一下就行了。
另外注意这不是费用流,不用跑\(spfa\),所以到了汇点直接退出,不然会超时。
代码如下:

#include<bits/stdc++.h>
#define mxn 100010
#define mxm 1010
using namespace std;
int m,n,cnt=1,st,ed;
int to[mxn],nxt[mxn],head[mxn],t[mxn];
int r[mxm],c[mxm],sum,ansmx,vis[mxn];
int flow[mxn],dep[mxn],use[mxn],pre[mxn];
void add_edge(int u,int v,int w)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w;
    head[u]=cnt;
    return;
}
bool bfs(int s)
{
    for(int i=0;i<=ed;i++)
        dep[i]=0,pre[i]=-1,vis[i]=0,flow[i]=1e15;
    dep[s]=1;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(vis[v]||t[i]==0)continue; 
            q.push(v);
            vis[v]=1;
            flow[v]=min(t[i],flow[u]);
            pre[v]=u;
            use[v]=i;
            if(v==ed)return 1;
        }
    } 
    return pre[ed]!=-1;
}
int dinic()
{
    while(bfs(st))
    {
        int u=ed;
        ansmx+=flow[ed];
        while(u)
        {
            t[use[u]]-=flow[ed];
            t[use[u]^1]+=flow[ed];
            u=pre[u];
        }
    } 
    return ansmx;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>m>>n;
    st=0,ed=n+m+1;
    for(int i=1;i<=m;i++)
    {
        int k;
        cin>>k;
        sum+=k; 
        add_edge(0,i,k);
        add_edge(i,0,0);
    }
    for(int i=1;i<=n;i++)
    {
        int k;
        cin>>k;
        add_edge(m+i,ed,k);
        add_edge(ed,m+i,0);
    }
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        {
            add_edge(i,m+j,1);
            add_edge(m+j,i,0);
        }
    int ret=dinic();
    if(ret!=sum)
    {
        cout<<0;
        return 0;
    }
    cout<<1<<'\n';
    for(int i=1;i<=m;i++,cout<<'\n')
        for(int j=m+1;j<ed;j++) 
            for(int k=head[j];k;k=nxt[k])
                if(to[k]==i&&t[k])
                    cout<<j-m<<' ';
    return 0;
}

T8 试题库问题

思路:最大流
这道题太典了,还是与上题一样,不过是建图方式变了。
源点连向试题,容量\(1\),每类题连向汇点,容量为规定数量。每道试题连向所属那一类,容量\(1\)。判无解和输出方案与T7类似。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define mxn 100010
#define mxm 1010
using namespace std;
int p,m,n,cnt=1,st,ed;
int to[mxn],nxt[mxn],head[mxn],t[mxn];
int r[mxm],c[mxm],sum,ansmx,vis[mxn];
int flow[mxn],dep[mxn],use[mxn],pre[mxn],pro[mxm];
void add_edge(int u,int v,int w)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w;
    head[u]=cnt;
    return;
}
bool bfs(int s)
{
    for(int i=0;i<=ed;i++)
        dep[i]=0,pre[i]=-1,vis[i]=0,flow[i]=1e15;
    dep[s]=1;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(vis[v]||t[i]==0)continue; 
            q.push(v);
            vis[v]=1;
            flow[v]=min(t[i],flow[u]);
            pre[v]=u;
            use[v]=i;
            if(v==ed)return 1;
        }
    } 
    return pre[ed]!=-1;
}
int dinic()
{
    while(bfs(st))
    {
        int u=ed;
        ansmx+=flow[ed];
        while(u)
        {
            t[use[u]]-=flow[ed];
            t[use[u]^1]+=flow[ed];
            u=pre[u];
        }
    } 
    return ansmx;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>p>>n;
    for(int i=1;i<=p;i++)
    {
        cin>>pro[i];
        m+=pro[i];
    }
    st=0,ed=n+p+1,cnt=1;
    for(int i=1;i<=p;i++)
    {
        add_edge(n+i,ed,pro[i]);        
        add_edge(ed,n+i,0);        
    }
    for(int i=1;i<=n;i++)
    {
        ll a;
        cin>>a;
        for(int j=1;j<=a;j++)
        {
            ll opt;
            cin>>opt;
            add_edge(i,n+opt,1);
            add_edge(n+opt,i,0); 
        }
    }
    for(int i=1;i<=n;i++)
    {
        add_edge(0,i,1);
        add_edge(i,0,0);
    }
    ll ans=dinic(); 
    if(ans!=m)
    {
        cout<<"No Solution!";
        return 0;
    }
    for(int i=1;i<=p;i++,cout<<'\n')
    {
        cout<<i<<':';
        for(int j=head[n+i];j;j=nxt[j])
            if(to[j]<=n&&t[j])
                cout<<to[j]<<' ';
    }
    return 0;
}

T9 骑士共存问题

思路:还是最大流
但是这题挺有趣,还带点思维。
我们观察到题干给出的图:

发现我们可以对棋盘交替染色,同色格子上的马互相攻击不到对方。所以我们可以建一个源点连向所有红色(或黄色,这里假设为红色)格子。然后将每个红色格连向它们能攻击到的黄色(只能是黄色)格子,再将黄色格子连向汇点。容量都设为\(1\),然后跑最大流。
注意这里的最大流是指红色格子能攻击到黄色格子的最大数量。所以最后统计是要减去它。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define mxn 6000010
#define mxm 2010
using namespace std;
int p,m,n,cnt=1,st,ed,cnt2;
ll to[mxn],nxt[mxn],head[mxn],t[mxn],cur[mxn];
ll mp[mxm][mxm],ansmx,vis[mxn];
ll dep[mxn],use[mxn],pre[mxn],pro[mxm];
ll dir[8][2]={{-2,-1},{-2,1},{2,-1},{2,1},{1,2},{-1,-2},{1,-2},{-1,2}};
inline ll getid(ll x,ll y)
{
    return (x-1)*n+y;
}
inline bool is_odd(ll x,ll y)
{
    if((x+y)%2==1) return 1;
    return 0;
}
void add_edge(ll u,ll v,ll w)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w;
    head[u]=cnt;
    return;
}
bool bfs(ll s)
{
    for(ll i=0;i<=ed;i++)
        dep[i]=0;
    dep[s]=1;
    queue<ll> q;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        for(ll i=head[u];i;i=nxt[i])
        {
            ll v=to[i];
            if(dep[v]||t[i]==0)continue; 
            dep[v]=dep[u]+1;
            q.push(v);   
        }
    } 
    return dep[ed];
}
ll dfs(ll u,ll fl)
{
    if(u==ed)
        return fl;
    ll flow=0;
    for(ll i=head[u];i;i=nxt[i])
    {
        if(flow==fl)return flow;
        ll v=to[i];
        if(t[i]>0&&dep[v]==dep[u]+1)
        {
            ll d=dfs(v,min(t[i],fl-flow));
            if(d>0)
            {
                t[i]-=d;
                t[i^1]+=d;
                flow+=d;
            }
        }
    }
    if(!flow)dep[u]=0;//一个小优化
    //如果分不出流就不用走了
    return flow;
}
ll dinic()
{
    while(bfs(st))
    {
        ll flg=1;
        while(flg)
        {
            flg=dfs(st,1e15);
            ansmx+=flg;
        }
    }
    return ansmx;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    st=0,ed=n*n+1;
    for(ll i=1;i<=m;i++)
    {
        ll u,v;
        cin>>u>>v;
        mp[u][v]=1;
    }
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=n;j++)
        {
            if(is_odd(i,j))
            {
                if(mp[i][j])continue;
                add_edge(0,getid(i,j),1);
                add_edge(getid(i,j),0,0);
                for(ll k=0;k<8;k++)
                {
                    ll fi=i+dir[k][0],fj=j+dir[k][1];
                    if(fi<1||fj<1||fi>n||fj>n||mp[fi][fj])continue;
                    add_edge(getid(i,j),getid(fi,fj),1);
                    add_edge(getid(fi,fj),getid(i,j),0);
                }
            }
            else
            {
                if(mp[i][j])continue;
                add_edge(getid(i,j),ed,1);
                add_edge(ed,getid(i,j),0);
            }
        }
    ll ans=dinic();
    cout<<n*n-m-ans;
    return 0;
}

T10 最长k可重区间集问题

思路:费用流
从这题开始,题单的难度再上一个层次,思维强度提升很大,不像之前几题一样套板子了。
这题第一眼看上去像一个匹配问题,把区间拆成点之后将每个区间匹配到对应的几个点上跑最大费用流。但是这里每个区间是强制匹配好几个点的,有点难搞。
这里的做法是把区间串起来,这样就可以强制匹配了。比如样例,我们可以这样建图:

其中,直线边容量为\(k\),费用为\(0\);曲线边容量为\(1\),费用为\(r-l\)。这样能保证当一段区间有\(k\)个重叠时,它后面的区间就没有流量了,可以试着手推一下。
另外,可以将拆出来的点离散化一下,最后跑一遍最大费用流就行了。
代码如下:

#include<bits/stdc++.h>
#define pil pair<long long,long long>
#define ll long long
#define mp make_pair
#define mxn 100010
#define mxm 1010
using namespace std;
ll n,k,ans,st,ed,vis[mxm],cnt2;
ll pre[mxm],dis[mxm],cnt;
ll head[mxn],to[mxn],val[mxn],t[mxn],nxt[mxn],w;
ll flow[mxn],use[mxn],b[mxm],x[mxm],y[mxm];
ll ansmx,ansmn,ls[mxm];
void lisan()
{
    sort(b+1,b+cnt2+1);
    int a=cnt2;
    cnt2=0;
    for(int i=1;i<=a;i++)
    {
        if(b[i]==b[i+1])continue;
        ls[++cnt2]=b[i];
    }
    for(int i=1;i<=n;i++)
    {
        x[i]=lower_bound(ls+1,ls+cnt2+1,x[i])-ls;
        y[i]=lower_bound(ls+1,ls+cnt2+1,y[i])-ls;
    }
    return;
}
void add_edge(ll u,ll v,ll w,ll c)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w,val[cnt]=c;
    head[u]=cnt;        
}
bool bfs(int s)
{
    for(int i=0;i<=n*2+1;i++)
        dis[i]=1e15,pre[i]=-1,vis[i]=0,flow[i]=1e15;
    vis[s]=1,dis[s]=0;
    queue<ll> q;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=nxt[i])
        {   
            ll v=to[i];
            if(dis[v]>dis[u]+val[i]&&t[i])
            {
                dis[v]=dis[u]+val[i];
                flow[v]=min(t[i],flow[u]);
                pre[v]=u,use[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return pre[ed]!=-1;
}
pil dinic()
{ 
    while(bfs(st))
    {
        int u=ed;
        ansmx+=flow[ed];
        ansmn+=flow[ed]*dis[ed];
        while(u)
        {
            t[use[u]]-=flow[ed];
            t[use[u]^1]+=flow[ed];
            u=pre[u];
        }
    }
    return make_pair(ansmx,ansmn);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>x[i]>>y[i];
        if(x[i]>y[i])swap(x[i],y[i]);
        b[++cnt2]=x[i],b[++cnt2]=y[i];
    }
    st=0,ed=n*2+1;
    cnt=1;
    lisan();
    st=0,ed=cnt2+1;
    for(int i=1;i<=cnt2;i++)
    {
        if(i==1)
        {
            add_edge(st,i,k,0);
            add_edge(i,st,0,0);
            continue;
        }
        add_edge(i-1,i,k,0);
        add_edge(i,i-1,0,0);
        if(i==cnt2)
        {
            add_edge(i,ed,k,0);
            add_edge(ed,i,0,0);
        }
    }
    for(int i=1;i<=n;i++)
    {
        add_edge(x[i],y[i],1,ls[x[i]]-ls[y[i]]);
        add_edge(y[i],x[i],0,ls[y[i]]-ls[x[i]]);
    }
    pil ansp=dinic();
    cout<<-ansp.second;
    return 0;
}

T11 方格取数问题

思路:最大流
先把题意翻译一下:“没有公共边”指的是选的任意两个格子不相邻。
咦?这题看起来怎么这么像骑士共存问题?只不过是将同色格与相邻格连起来而已。建图时,源点连向黑色点(假定为黑色)时,容量为黑色点的点权;白色点连向汇点时,容量为白色点的点权;黑色点连向白色点时,容量无限大;然后我们就可以开心跑最大流了。
还有一点要注意的地方:此题\(m\)可能小于\(n\),所以取编号时注意一下。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define mxn 6000010
#define mxm 2010
using namespace std;
int p,m,n,cnt=1,st,ed,cnt2;
ll to[mxn],nxt[mxn],head[mxn],t[mxn],cur[mxn];
ll mp[mxm][mxm],ansmx,vis[mxn],sum;
ll dep[mxn],use[mxn],pre[mxn],pro[mxm];
ll dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
inline ll getid(ll x,ll y)
{
	if(n<m)return (y-1)*m+x;
	return (x-1)*n+y;
}
inline bool is_odd(ll x,ll y)
{
    if((x+y)%2==1) return 1;
    return 0;
}
void add_edge(ll u,ll v,ll w)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w;
    head[u]=cnt;
    return;
}
bool bfs(ll s)
{
    for(ll i=0;i<=ed;i++)
        dep[i]=0;
    dep[s]=1;
    queue<ll> q;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        for(ll i=head[u];i;i=nxt[i])
        {
            ll v=to[i];
            if(dep[v]||t[i]==0)continue; 
            dep[v]=dep[u]+1;
            q.push(v);   
        }
    } 
    return dep[ed];
}
ll dfs(ll u,ll fl)
{
    if(u==ed)
        return fl;
    ll flow=0;
    for(ll i=head[u];i;i=nxt[i])
    {
        if(flow==fl)return flow;
        ll v=to[i];
        if(t[i]>0&&dep[v]==dep[u]+1)
        {
            ll d=dfs(v,min(t[i],fl-flow));
            if(d>0)
            {
                t[i]-=d;
                t[i^1]+=d;
                flow+=d;
            }
        }
    }
    if(!flow)dep[u]=0;
    return flow;
}
ll dinic()
{
    while(bfs(st))
    {
        ll flg=1;
        while(flg)
        {
            flg=dfs(st,1e15);
            ansmx+=flg;
        }
    }
    return ansmx;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>m>>n;
    st=0,ed=m*n+1;
    for(ll i=1;i<=m;i++)
        for(ll j=1;j<=n;j++)
        {
            cin>>mp[i][j];
            sum+=mp[i][j];
        }
    for(ll i=1;i<=m;i++)
        for(ll j=1;j<=n;j++)
        {
            if(is_odd(i,j))
            {
                add_edge(0,getid(i,j),mp[i][j]);
                add_edge(getid(i,j),0,0);
                for(ll k=0;k<4;k++)
                {
                    ll fi=i+dir[k][0],fj=j+dir[k][1];
                    if(fi<1||fj<1||fi>m||fj>n)continue;
                    add_edge(getid(i,j),getid(fi,fj),1e15);
                    add_edge(getid(fi,fj),getid(i,j),0);
                }
            }
            else
            {
                add_edge(getid(i,j),ed,mp[i][j]);
                add_edge(ed,getid(i,j),0);
            }
        }
    ll ans=dinic();
    cout<<sum-ans;
    return 0;
}

T12 汽车加油行驶问题

思路:记忆化搜索费用流
好吧我们还是讲一讲记忆化搜索的解法

一、记忆化搜索(来自mzy4003大佬的题解
其实我一开始也只想到了搜索
我们设\(f[x][y][z]\)为到了\((x,y)\)且剩余步数为\(z\)时的最小费用。初始化为无限大,若当前费用大于最小费用(以及剩余步数大于\(z\)时的状态的最小费用),则进行剪枝。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,k,a,b,c,mp[110][110],f[110][110][11],ans=1e9;
void dfs(int x,int y,int m,int step)
{
    if(x<1||y<1||x>n||y>n)return;
    if(m>=ans)return;
    step--;
    for(int i=step;i<=k;i++)
        if(m>=f[x][y][i])return;
    f[x][y][step]=m;
    if(x==n&&y==n)
    {
        ans=min(ans,m);
        return;
    }
    if(mp[x][y])m+=a,step=k;
    if(step==0)m+=a+c,step=k;
    dfs(x+1,y,m,step);
    dfs(x,y+1,m,step);
    dfs(x-1,y,m+b,step);
    dfs(x,y-1,m+b,step);    
    return;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>k>>a>>b>>c;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>mp[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int l=0;l<=k;l++)
                f[i][j][l]=1e9;
    dfs(1,1,0,k+1);
    cout<<ans;
    return 0;
} 

这上面的剪枝,少一个都会\(TLE\)!

二、网络流
若无流量限制,很容易想到源点连向\((1,1)\),\((n,n)\)连向汇点,费用为\(0\);向右下走的费用为\(0\),向左上走的费用为\(b\)。所有边容量为\(1\),跑最小费用流就行了,但这里有油量限制,有点难搞。
这时我们就要推出一个全新的东西:分层图
把图分成\(k+1\)层,第一层为满油,第二层为\(k-1\)格油,依此类推,第\(k+1\)层为\(0\)格油。
连边时这样连:
若\((i,j)\)处无加油站,就在往旁边连的时候往上连一层,费用\(0\)。若到了第\(k+1\)层就往第一层连一条费用为\(a+c\)的边。
若\((i,j)\)处有加油站,就往第一层连,费用为\(a\);
若是往左上连,费用还要多加一个\(b\);
源点连向第一层的\((1,1)\);每一层的\((n,n)\)都连向源点。最后跑一遍最小费用流就行了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define mxn 1000010
#define mxm 110010
using namespace std;
int n,k,a,b,c,ans,st,ed,vis[mxm],ansc;
int pre[mxm],dis[mxm],cnt;
int head[mxn],to[mxn],val[mxn],t[mxn],nxt[mxn],w;
int sum,flow[mxn],use[mxn];
int ansmx,ansmn,mp[110][110],dir[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
inline void add_edge(int u,int v,int w,int c)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    t[cnt]=w,val[cnt]=c;
    head[u]=cnt;        
}
int getid(int x,int y,int k)
{
    return (x-1)*n+y+(k-1)*n*n;
}
bool bfs(int s)
{
    for(int i=0;i<=ed;i++)
        dis[i]=1e15,pre[i]=0,vis[i]=0;
    vis[s]=1,dis[s]=0,flow[s]=1e15;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=nxt[i])
        {   
            int v=to[i];
            if(dis[v]>dis[u]+val[i]&&t[i])
            {
                dis[v]=dis[u]+val[i];
                flow[v]=min(t[i],flow[u]);
                pre[v]=u,use[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return pre[ed]!=0;
}
pair<int,int> dinic()
{ 
    while(bfs(st))
    {
        int u=ed;
        ansmx+=flow[ed];
        ansmn+=flow[ed]*dis[ed];
        while(u)
        {
            t[use[u]]-=flow[ed];
            t[use[u]^1]+=flow[ed];
            u=pre[u];
        }
    }
    return make_pair(ansmx,ansmn);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>k>>a>>b>>c;
    st=0,ed=n*n*(k+1)+1;
    add_edge(0,1,1,0);
    add_edge(1,0,0,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            cin>>mp[i][j];
            if(!mp[i][j])
            {
                for(int p=0;p<4;p++)
                {
                    int fi=i+dir[p][0],fj=j+dir[p][1];
                    if(fi<1||fj<1||fi>n||fj>n)continue;
                    for(int l=1;l<=k;l++)
                    {
                        if(p<2)add_edge(getid(i,j,l),getid(fi,fj,l+1),1,0),add_edge(getid(fi,fj,l+1),getid(i,j,l),0,0);
                        else add_edge(getid(i,j,l),getid(fi,fj,l+1),1,b),add_edge(getid(fi,fj,l+1),getid(i,j,l),0,-b);
                    }
                    if(p<2)add_edge(getid(i,j,k+1),getid(fi,fj,2),1,a+c),add_edge(getid(fi,fj,2),getid(i,j,k+1),0,-a-c);
                    else add_edge(getid(i,j,k+1),getid(fi,fj,2),1,a+b+c),add_edge(getid(fi,fj,2),getid(i,j,k+1),0,-a-b-c);
                }   
            }
            else
            {
                for(int p=0;p<4;p++)
                {
                    int fi=i+dir[p][0],fj=j+dir[p][1];
                    if(fi<1||fj<1||fi>n||fj>n)continue;
                    for(int l=1;l<=k+1;l++)
                    {
                        if(p<2)add_edge(getid(i,j,l),getid(fi,fj,2),1,a),add_edge(getid(fi,fj,2),getid(i,j,l),0,-a);
                        else add_edge(getid(i,j,l),getid(fi,fj,2),1,a+b),add_edge(getid(fi,fj,2),getid(i,j,l),0,-a-b);
                    }
                }
            }
            if(i==n&&j==n)
                for(int l=1;l<=k+1;l++)
                    add_edge(getid(i,j,l),ed,1,0),add_edge(ed,getid(i,j,l),0,0);
        }
    pii ansp=dinic();
    cout<<ansp.second;
    return 0;
}

观察代码,容易发现每条边的容量都是\(1\),于是完全可以把容量去掉,就变成了求最短路,跑一遍\(SPFA/dijkstra\)就行了。

古语有云:行百里者半五十,我们已经完成一半了,继续前进吧!

标签:24,cnt,线性规划,ed,ll,flow,mxn,int,详解
From: https://www.cnblogs.com/nagato--yuki/p/18442991

相关文章

  • ABC373 D-F 详解
    D思路说是有向图,实际上可以看作是无向图。因为如果有\(x_{v_j}-x_{u_j}=w_j\),那么就一定有\(x_{u_j}-x_{v_j}=-w_j\)。因为题目保证给出的数量关系没有冲突,所以如果我们知道了一个结点\(a\)的值,那么所有与它有数量关系的结点\(b\)的值都能被推出。从而如果一个连......
  • CSP2024-30
    A题意:将一个圆等分为\(K\)分,给出其中\(n\)个等分点的编号,\(x_i<x_{i+1}\)。有向边\(i\toj\)存在,当且仅当\(j\)是距离\(i\)最大的点(不唯一),且与图中其他边无交点(端点不算)。求图中最多有多少条边。\(3\leK\le10^9,3\len\le\min(K,10^5)\)。引理:不存在......
  • The 2024 ICPC Asia East Continent Online Contest (II)
    A.GamblingonChoosingRegionals最差情况就是,强队都和你去一起。因此赛站越小,排名也一定越小。然后只要动态实现出每个学校最强的若干只队伍就好了。#include<bits/stdc++.h>usingnamespacestd;usingi32=int32_t;usingi64=longlong;#defineinti64using......
  • 2024 北京市大学生程序设计竞赛
    Preface北京市赛(×),小WF(确信)感觉这场题总体都挺难的,除了前1h出了两个题后,后面基本上都是1h出一题然后最后1h发生了经典的我和徐神B,F双开双会,最后开始抢机时,最后经典的一个没写出来赛后发现F赛时代码改个初值就能过了,而徐神多花了半小时也是成功把B过了只能说还......
  • 文心一言 VS 讯飞星火 VS chatgpt (359)-- 算法导论24.3 1题
    一、在图24-2上运行Dijkstra算法,第一次使用结点作为源结点,第二次使用结点作为源结点。以类似于图24-6的风格,给出每次while循环后的值和值,以及集合中的所有结点。如果要写代码,请用go语言。文心一言:在图24-2上运行Dijkstra算法,我们可以模拟算法的执行过程,并给出每次while循......
  • leetcode24 两两交换链表中的节点(swap-nodes-in-pairs)
    题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。示例1:输入:head=[1,2,3,4]输出:[2,1,4,3]示例2:输入:head=[]输出:[]示例3:输入:head=[1]输出:[1] 提示:链表中节点的数......
  • 论文总结1--基于深度强化学习的四足机器人步态分析--2024.10.01
    四足机器人的运动控制方法研究1.传统运动控制-基于模型的控制方法  目前,在四足机器人研究领域内应用最广泛的控制方法就是基于模型的控制方法,其中主要包括基于虚拟模型控制(VirtualModelControl,VMC)方法、基于零力矩点(ZeroMomentPoint,ZMP)的控制方法、弹簧负载倒立摆算法......
  • 页面缓存详解
    在学习Swagger的时候刚开始使用Swagger3.x但是有些配置还是使用之前版本的,所以就一直报404,在查阅一些网上的资料后,(现在还不知道是版本配置问题)大多数都是让清除以下缓存,我知道怎么清除(平时的清除缓存一般指的是清除浏览器缓存),当然之前也零散的接触过一些关于缓存的知识,但是没......
  • 【训练记录】2024年莆田市高中信息学奥赛国庆集训CSP-S提高组(第一天场外)
    训练情况rank#15\(100+0+40+0=140\)赛后反思T3忘记负数取模,丢了\(60\)分T1.跑步显然,找到第一个大于\(t\)的\(a,b,c\)倍数,所以我们直接\(t\diva,b,c\)向上取整,再乘回去,最后减去\(t\)即可,注意一下ceil好像会爆#include<bits/stdc++.h>#definei......
  • 视频编辑软件Adobe Premiere PR2024软件下载安装
    目录简介下载安装安装步骤软件特点使用教程简介AdobePremiere(简称Pr)是由Adobe公司开发的一款功能强大的视频编辑软件。它支持多平台运行,包括Windows、MacOS和Linux系统,为视频编辑爱好者和专业人士提供了丰富的工具集。Premiere以其出色的编辑画面质量、良好的兼容性......