hdu3549Flow Problem poj1273Drainage Ditches poj3281Dining sgu185 Network flow

hdu3549Flow_Problem

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5005;
const int M = 30005;
struct Enode{
    int y, c, next;
} e[M * 2];
//struct Point
//{
//	int son,cur,pre,lim,d;
//} a[maxn];
int n, m, tot, head[N], now[N], h[N], vh[N], augc, found, flow;
//h为距离,vh为距离标号的数目,augc当前边的流量,flow总流量
//int tot, n, m, st, ed, cnt[maxn];
void Addedge(int x, int y, int c){
    e[++tot].y = y; e[tot].c = c; e[tot].next = head[x]; head[x] = tot;
    e[++tot].y = x; e[tot].c = 0; e[tot].next = head[y]; head[y] = tot;
}
void Init(){
    int x, y, c, i;
    scanf("%d%d", &n, &m);
    tot = -1; memset(head, -1, sizeof(head));
    for (i = 0; i < m; i++){
        scanf("%d%d%d", &x, &y, &c);
        Addedge(x, y, c);
    }
    memcpy(now, head, sizeof(head));
}

void Aug(int x, int st, int ed, int n){//x当前点,st源点,ed汇点,n,点最大数目
    int p = now[x], minh = n - 1, augco = augc;
    if (x == ed){
        found = 1;
        flow += augc;
        return;
    }
    while (p != -1){//每条边
        if (e[p].c > 0 && h[e[p].y] + 1 == h[x]){//e[p].y下一点,可行弧
            augc = min(augc, e[p].c);
            Aug(e[p].y, st, ed, n);//下一点
            if (h[st] >= n) return;
            if (found) break;
            augc = augco;
        }
        p = e[p].next;//下一边
    }
    if (found){
        e[p].c -= augc;
        e[p ^ 1].c += augc;//边标号从0开始,反向边,p^1
    }else{
        p = head[x];
        while (p != -1){
            if (e[p].c > 0 && h[e[p].y] < minh){
                minh = h[e[p].y];//最小标号
                now[x] = p;
            }
            p = e[p].next;
        }
        vh[h[x]] --;//标号数目-1
        if (!vh[h[x]]) h[st] = n;//无符合标号
        h[x] = minh + 1;//修改当前节点标号
        vh[h[x]] ++;
    }
}
void Maxflow(int st, int ed, int n){
    flow = 0;
    memset(h, 0, sizeof(h));
    memset(vh, 0, sizeof(vh));
    vh[0] = n;//距离标号的数目
    while (h[st] < n){
        found = 0;
        augc = 1 << 30;//假设流量无穷大
        Aug(st, st, ed, n);
    }
}
int main(){
    int T,cas=0;
    scanf("%d",&T);
    while(T--){
        Init();
        Maxflow(1, n, n);
        printf("Case %d: %d\n",++cas, flow);
    }
    return 0;
}
poj1273Drainage Ditches
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 2222
#define MAXM 444444 //邻接表要开边数的2倍
#define inf 1<<30

struct Edge {
    int v,cap,next;
} edge[MAXM];

int n,m,vs,vt,NE,NV;
int head[MAXN];

void Insert(int u,int v,int cap)
{
    edge[NE].v=v;
    edge[NE].cap=cap;
    edge[NE].next=head[u];
    head[u]=NE++;

    edge[NE].v=u;
    edge[NE].cap=0;
    edge[NE].next=head[v];
    head[v]=NE++;
}

int level[MAXN];//标记层次(距离标号)
int gap[MAXN];
//间隙优化,定义gap[i]为标号是i的点的个数
//在重标记i时,检查gap[level[i]],若减为0,这算法结束。

void bfs(int vt)
{
    memset(level,-1,sizeof(level));
    memset(gap,0,sizeof(gap));
    level[vt]=0;
    gap[level[vt]]++;
    queue<int>que;
    que.push(vt);
    while(!que.empty()) {
        int u=que.front();
        que.pop();
        for(int i=head[u]; i!=-1; i=edge[i].next) {
            int v=edge[i].v;
            if(level[v]!=-1)continue;
            level[v]=level[u]+1;
            gap[level[v]]++;
            que.push(v);

        }
    }
}


int pre[MAXN];//前驱
int cur[MAXN];

int SAP(int vs,int vt)//源点,汇点
{
    bfs(vt);//bfs优化,
    memset(pre,-1,sizeof(pre));
    memcpy(cur,head,sizeof(head));//cur保存的是当前弧
    int u=pre[vs]=vs,flow=0,aug=inf;//源点前驱还是它本身,aug表示增广路的可改尽量
    gap[0]=NV;
    while(level[vs]<NV) {
        bool flag=false;
        for(int &i=cur[u]; i!=-1; i=edge[i].next) {
            int v=edge[i].v;//v是u的后继
            //寻找可行弧
            if(edge[i].cap&&level[u]==level[v]+1) {
                flag=true;//找到可行弧
                pre[v]=u;//记录前驱
                u=v;
                //  aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
                aug=min(aug,edge[i].cap);
                //如果找到 一条增广路
                if(v==vt) {
                    flow+=aug;//更新最大流
                    for(u=pre[v]; v!=vs; v=u,u=pre[u]) {
                        edge[cur[u]].cap-=aug;//前向弧容量减少
                        edge[cur[u]^1].cap+=aug;//后向弧容量增加
                    }
                    //     aug=-1;
                    aug=inf;
                }
                break;
            }
        }
        if(flag)continue;
        int minlevel=NV;
        //寻找与当前点相连接的点中最小的距离标号(重标号)
        for(int i=head[u]; i!=-1; i=edge[i].next) {
            int v=edge[i].v;
            if(edge[i].cap&&level[v]<minlevel) {
                minlevel=level[v];
                cur[u]=i;
            }
        }
        if(--gap[level[u]]==0)break;//更新gap数组后若出现断层,直接退出
        level[u]=minlevel+1;//重标号
        gap[level[u]]++;//距离标号为level[u]的点的个数+1
        u=pre[u];//转为当前节点的前驱继续寻找可行弧
    }
    return flow;
}
int main()
{
    int u,v,w,w1,w2;
    while(scanf("%d%d",&m,&n)==2){
        vs=0;
        vt=n-1;
        NV=n;//总点数
        NE=0;
        memset(head,-1,sizeof(head));
        for(int i=1; i<=m; i++) {
            scanf("%d%d%d",&u,&v,&w);
            Insert(--u,--v,w);
        //Insert(v,u,w);
        }
        printf("%d\n",SAP(vs,vt));
    }
    return 0;
}
poj3281Dining
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5005;
const int M = 30005;
struct Enode{
    int y, c, next;
} e[M * 2];
//struct Point
//{
//	int son,cur,pre,lim,d;
//} a[maxn];
int n, m, tot, head[N], now[N], h[N], vh[N], augc, found, flow;
//h为距离,vh为距离标号的数目,augc当前边的流量,flow总流量
//int tot, n, m, st, ed, cnt[maxn];
void Addedge(int x, int y, int c){
    e[++tot].y = y; e[tot].c = c; e[tot].next = head[x]; head[x] = tot;
    e[++tot].y = x; e[tot].c = 0; e[tot].next = head[y]; head[y] = tot;
}
int f,d;
void Init(){
    int x, y, c, i,tmp;
    scanf("%d%d%d", &n, &f, &d);
    tot = -1; memset(head, -1, sizeof(head));
    for (i = 1; i <= n; i++){
        scanf("%d%d", &x, &y);
        while(x--){
            scanf("%d",&tmp);
            Addedge(0,tmp,1);
            //Addedge(tmp,f+i,1);在这里可能会加重了
        }
        Addedge(i+f,i+f+n,1);
        while(y--){
            scanf("%d",&tmp);
            Addedge(i+n+f,f+2*n+tmp,1);
            //Addedge(f+2*n+tmp,f+2*n+d+1,1);
        }
    }
    for(int j=1;j<=f;j++) Addedge(j,i+f,1);
    for(int j=1;j<=d;j++) Addedge(j+f+n*2,d+f+n*2+1,1);
    memcpy(now, head, sizeof(head));
}

void Aug(int x, int st, int ed, int n){//x当前点,st源点,ed汇点,n,点最大数目
    int p = now[x], minh = n-1, augco = augc;
    if (x == ed){
        found = 1;
        flow += augc;
        return;
    }
    while (p != -1){//每条边
        if (e[p].c > 0 && h[e[p].y] + 1 == h[x]){//e[p].y下一点,可行弧
            augc = min(augc, e[p].c);
            Aug(e[p].y, st, ed, n);//下一点
            if (h[st] >= n) return;
            if (found) break;
            augc = augco;
        }
        p = e[p].next;//下一边
    }
    if (found){
        e[p].c -= augc;
        e[p ^ 1].c += augc;//边标号从0开始,反向边,p^1
    }else{
        p = head[x];
        while (p != -1){
            if (e[p].c > 0 && h[e[p].y] < minh){
                minh = h[e[p].y];//最小标号
                now[x] = p;
            }
            p = e[p].next;
        }
        vh[h[x]] --;//标号数目-1
        if (!vh[h[x]]) h[st] = n;//无符合标号
        h[x] = minh + 1;//修改当前节点标号
        vh[h[x]] ++;
    }
}
void Maxflow(int st, int ed, int n){
    flow = 0;
    memset(h, 0, sizeof(h));
    memset(vh, 0, sizeof(vh));
    vh[0] = n;//距离标号的数目
    while (h[st] < n){
        found = 0;
        augc = 1 << 30;//假设流量无穷大
        Aug(st, st, ed, n);
    }
}
int main(){
    Init();
    Maxflow(0, 2*n+f+d+1, 2*n+f+d+2);
    printf("%d\n", flow);
}
sgu185
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 444
#define MAXM 160002 //邻接表要开边数的2倍
#define inf 1<<30
#define INF 1<<30
#define maxn 444
bool vis[maxn];
int adj[maxn][maxn],dis[maxn];//pre[]记录前驱
int n, m;
void dijkstra(int v)
{
    int i, j, u , min;
    for(i=0;i<=n;i++)  {
        dis[i]=adj[v][i];
        vis[i]=0;
    }
    vis[v]=1;dis[v]=0;
    for(i=1;i<=n;i++)   {
        min = INF;
        for(j=1;j<=n;j++)
            if(!vis[j]&&min > dis[j]){
                min = dis[j];
                u = j;
            }
        if(min == INF)break;
        vis[u]=1;
        for(j=1;j<=n;j++){
            if(!vis[j]&&adj[u][j]!=INF&&dis[u]+adj[u][j]<dis[j])
                dis[j] = adj[u][j] + dis[u];
        }
    }
}
struct Edge {
    int v,cap,next;
} edge[MAXM];

int vs,vt,NE,NV;
int head[MAXN];

void Insert(int u,int v,int cap)
{
    edge[NE].v=v;
    edge[NE].cap=cap;
    edge[NE].next=head[u];
    head[u]=NE++;

    edge[NE].v=u;//反向边
    edge[NE].cap=0;
    edge[NE].next=head[v];
    head[v]=NE++;
}
void make_graph(){
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
        if(i==j||adj[i][j]==INF) continue;
        if(dis[i]+adj[i][j]==dis[j]){
            Insert(i-1,j-1,1);
            //Insert(j-1,i-1,1);
            //printf("edge:%d %d\n",i,j);
        }
    }
}
int level[MAXN];//标记层次(距离标号)
int gap[MAXN];
//间隙优化,定义gap[i]为标号是i的点的个数
//在重标记i时,检查gap[level[i]],若减为0,这算法结束。

void bfs(int vt)
{
    memset(level,-1,sizeof(level));
    memset(gap,0,sizeof(gap));
    level[vt]=0;
    gap[level[vt]]++;
    queue<int>que;
    que.push(vt);
    while(!que.empty()) {
        int u=que.front();
        que.pop();
        for(int i=head[u]; i!=-1; i=edge[i].next) {
            int v=edge[i].v;
            if(level[v]!=-1)continue;
            level[v]=level[u]+1;
            gap[level[v]]++;
            que.push(v);
        }
    }
}
int pre[MAXN];//前驱
int cur[MAXN];

int SAP(int vs,int vt)//源点,汇点
{
    bfs(vt);//bfs优化,
    memset(pre,-1,sizeof(pre));
    memcpy(cur,head,sizeof(head));//cur保存的是当前弧
    int u=pre[vs]=vs,flow=0,aug=inf;//源点前驱还是它本身,aug表示增广路的可改尽量
    gap[0]=NV;
    while(level[vs]<NV) {
        bool flag=false;
        for(int &i=cur[u]; i!=-1; i=edge[i].next) {
            int v=edge[i].v;//v是u的后继
            //寻找可行弧
            if(edge[i].cap&&level[u]==level[v]+1) {
                flag=true;//找到可行弧
                pre[v]=u;//记录前驱
                u=v;
                //  aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
                aug=min(aug,edge[i].cap);
                //如果找到 一条增广路
                if(v==vt) {
                    flow+=aug;//更新最大流
                    for(u=pre[v]; v!=vs; v=u,u=pre[u]) {
                        edge[cur[u]].cap-=aug;//前向弧容量减少
                        edge[cur[u]^1].cap+=aug;//后向弧容量增加
                    }
                    //     aug=-1;
                    aug=inf;
                }
                break;
            }
        }
        if(flag)continue;
        int minlevel=NV;
        //寻找与当前点相连接的点中最小的距离标号(重标号)
        for(int i=head[u]; i!=-1; i=edge[i].next) {
            int v=edge[i].v;
            if(edge[i].cap&&level[v]<minlevel) {
                minlevel=level[v];
                cur[u]=i;
            }
        }
        if(--gap[level[u]]==0)break;//更新gap数组后若出现断层,直接退出
        level[u]=minlevel+1;//重标号
        gap[level[u]]++;//距离标号为level[u]的点的个数+1
        u=pre[u];//转为当前节点的前驱继续寻找可行弧
    }
    //cout<<'f'<<flow<<endl;
    return flow;
}
bool flag;//flag的作用
void dfs(int u){///输出路径
    if(flag) return ;
    if(u==n-1){
        flag=true;
        cout<<endl;
        return ;
    }
    for(int i=head[u];i!=-1&&!flag;i=edge[i].next){
        int v=edge[i].v;
        if(edge[i].cap==0 && !(i&1)){///
            edge[i].cap=-1;
            cout<<' '<<v+1;
            dfs(v);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++)for(int j=0;j<=n;j++){
        if(i==j)adj[i][j]=0;
        else adj[i][j]=INF;
    }
    for(int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        adj[x][y]=adj[y][x]=z;
    }
    dijkstra(1);
    //cout<<' '<<dis[n]<<endl;
    vs=0;
    vt=n-1;
    NV=n;//总点数
    NE=0;
    memset(head,-1,sizeof(head));
    make_graph();//位置= =
    if(SAP(vs,vt)<2)printf("No solution\n");
    else{
        cout<<1;
        flag=false;
        dfs(0);
        //cout<<'a'<<endl;
        cout<<1;
        flag=false;
        dfs(0);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值