2023/4/11小记

多源汇最大流

建一个超级原点,一个超级汇点就行,注意数组大小。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+6,M=1e6+5;
class Dinic{
    public :
    const int INF=2e9;
    inline void add(int u,int v,int w){
        AddEdge(u,v,w);
        AddEdge(v,u,0);
    }
    int S,T;
    int do_Dinic(){
        int ret=0;
        while(bfs()){
            ret+=dfs(S,INF);
        }
        return ret;
    }
    void set_ST(int ss,int tt){S=ss,T=tt;}
    private :
    int hd[N],cur[N],cntedge=1;
    struct node{int to,val,nxt;}a[N];
    inline void AddEdge(int u,int v,int w){
        a[++cntedge]=(node){v,w,hd[u]};
        hd[u]=cntedge;
    }
    int dis[N];
    bool bfs(){
        memset(dis,-1,sizeof(dis));
        memcpy(cur,hd,sizeof(hd));
        queue<int> q;
        q.push(S);dis[S]=0;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=hd[u];i;i=a[i].nxt){
                int to=a[i].to;
                if(dis[to]==-1&&a[i].val){
                    dis[to]=dis[u]+1;
                    q.push(to);
                }
            }
        }
        return dis[T]!=-1;
    }
    int dfs(int u,int flow){
        if(u==T) return flow;
        int now=0;
        for(int i=cur[u];i&&now<flow;i=a[i].nxt){
            cur[u]=i;
            int to=a[i].to;
            if(dis[to]==dis[u]+1&&a[i].val){
                int dlt=dfs(to,min(flow-now,a[i].val));
                a[i].val-=dlt,a[i^1].val+=dlt;
                now+=dlt;
            }
        }
        return now;
    }
}D;
int n,m,cnts,cntt;
int main(){
    scanf("%d%d",&n,&m);
    scanf("%d%d",&cnts,&cntt);
    D.set_ST(n+1,n+2);
    for(int i=1;i<=cnts;i++){
        int tmp;scanf("%d",&tmp);
        D.add(D.S,tmp,D.INF);
    }
    for(int i=1;i<=cntt;i++){
        int tmp;scanf("%d",&tmp);
        D.add(tmp,D.T,D.INF);
    }
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        D.add(u,v,w);
    }
    cout<<D.do_Dinic();
    return 0;
}

最大密度子图

首先二分答案;
分数规划:
\(\frac{E}{V} \ge mid\)转化成 \(E-V\times mid\ge 0\)

然后建图。

选一个点的花销是mid,不选这个点的代价是失去这个点出去的边。
我建的图是这个东西反过来 问题不大。输出答案好讨厌qwq。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=1e5+5;
template<class T>void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9')  {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;return;
}
#define db double
bool vis[N];
int ans;
int n,m,k;
class Dinic{
    public :
    const db INF=2e9;
    inline void add(int u,int v,db w){
        AddEdge(u,v,w);
        AddEdge(v,u,0);
    }
    int S,T;
    int do_Dinic(){
        db ret=0;
        while(bfs()){
            ret+=dfs(S,INF);
        }
        return ret;
    }
    void set_ST(int ss,int tt){S=ss,T=tt;}
    inline void init(){
        memset(hd,0,sizeof(hd));
        cntedge=1;
    }
    void findans(int u){
        if(u>=1&&u<=n) ans++;
        vis[u]=1;
        for(int i=hd[u];i;i=a[i].nxt)
        if(!vis[a[i].to]&&a[i].val>0)findans(a[i].to);
        return ;
    }
    private :
    int hd[N],cur[N],cntedge=1;
    struct node{int to;db val;int nxt;}a[N];
    inline void AddEdge(int u,int v,db w){
        a[++cntedge]=(node){v,w,hd[u]};
        hd[u]=cntedge;
    }
    int dis[N];
    bool bfs(){
        memset(dis,-1,sizeof(dis));
        memcpy(cur,hd,sizeof(hd));
        queue<int> q;
        q.push(S);dis[S]=0;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=hd[u];i;i=a[i].nxt){
                int to=a[i].to;
                if(dis[to]==-1&&a[i].val){
                    dis[to]=dis[u]+1;
                    q.push(to);
                }
            }
        }
        return dis[T]!=-1;
    }
    db dfs(int u,db flow){
        if(u==T) return flow;
        db now=0;
        for(int i=cur[u];i&&now<flow;i=a[i].nxt){
            cur[u]=i;
            int to=a[i].to;
            if(dis[to]==dis[u]+1&&a[i].val){
                db dlt=dfs(to,min(flow-now,a[i].val));
                a[i].val-=dlt,a[i^1].val+=dlt;
                now+=dlt;
            }
        }
        return now;
    }
}D;
struct NODE{int fr,to;}s[N];
bool check(db x){
    D.init();
    D.set_ST(n+m+1,n+m+2);
    for(int i=1;i<=n;i++)D.add(D.S,i,x);
    // for(int i=1;i<=n;i++)D.add(i,D.T,D.INF);
    for(int i=1;i<=m;i++){
        int tmp=n+i;
        D.add(s[i].fr,tmp,1);
        D.add(s[i].to,tmp,1);
        D.add(tmp,D.T,1);
    }
    return m>D.do_Dinic();
}
int main(){
    read(n),read(m);
    for(int i=1;i<=m;i++){
        read(s[i].fr),read(s[i].to);
    }
    db l=0,r=1e4,mid,eps=1e-8;
    while(r-l>eps){
        mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    // cout<<check(1)<<" "<<check(1.19)<<" "<<check(1.25)<<endl;
    check(l);
    // debug(l);
    D.findans(D.S);
    if(l==0){
        printf("1\n1");return 0;
    }
    printf("%d\n",n-ans);
    for(int i=1;i<=n;i++)
    if(!vis[i]) printf("%d\n",i);
    return 0;
}

[HNOI2013]切糕
不考虑D的限制的时候是好做的
image.png
考虑D的限制
这样
这时候如果这种选择会强迫割下一个INF,不会这么走,就行了。

dinic板子

class Dinic{
    public :
    const int INF=2e9;
    inline void add(int u,int v,int w){
        AddEdge(u,v,w);
        AddEdge(v,u,0);
    }
    int S,T;
    int do_Dinic(){
        int ret=0;
        while(bfs()){
            ret+=dfs(S,INF);
        }
        return ret;
    }
    void set_ST(int ss,int tt){S=ss,T=tt;}
    private :
    int hd[N],cur[N],cntedge=1;
    struct node{int to,val,nxt;}a[M<<1];
    inline void AddEdge(int u,int v,int w){
        a[++cntedge]=(node){v,w,hd[u]};
        hd[u]=cntedge;
    }
    int dis[N];
    bool bfs(){
        memset(dis,-1,sizeof(dis));
        memcpy(cur,hd,sizeof(hd));
        queue<int> q;
        q.push(S);dis[S]=0;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=hd[u];i;i=a[i].nxt){
                int to=a[i].to;
                if(dis[to]==-1&&a[i].val){
                    dis[to]=dis[u]+1;
                    q.push(to);
                }
            }
        }
        return dis[T]!=-1;
    }
    int dfs(int u,int flow){
        if(u==T) return flow;
        int now=0;
        for(int i=cur[u];i&&now<flow;i=a[i].nxt){
            cur[u]=i;
            int to=a[i].to;
            if(dis[to]==dis[u]+1&&a[i].val){
                int dlt=dfs(to,min(flow-now,a[i].val));
                a[i].val-=dlt,a[i^1].val+=dlt;
                now+=dlt;
            }
        }
        return now;
    }
}D;

每日发癫

循着风 逆着光 告别月亮
记忆收拢 温暖过往
莫思 也莫遗忘 离别时 接过他勋章
于未来 的未来 共迎春光
莫思 也莫遗忘 用生命凝塑 的画像
永不湮灭 爱是穿越一切 的力量
(阿良良老师的莫思)

posted @ 2023-04-11 19:40  洛浔  阅读(39)  评论(0编辑  收藏  举报