网络流小结

1532Drainage Ditches(基础)    [最大流]
3549 Flow Problem(基础)    [最大流]
3572 Task Schedule    [最大流]任务分配,判断满流
2732 Leapin' Lizards(难)    [最大流]
3338 Kakuro Extension    [最大流][数和]神奇最大流行进列出
3605 Escape    [最大流](多重匹配)
4183 Pahom on Water    [最大流]来回走不重复点的网络流.
4240 Route Redundancy    [最大流]一条流最大的路径
3081 Marriage Match II    [二分最大流]+并查集
3277 Marriage Match III    [二分最大流]同上,多了拆点
3416 Marriage Match IV    [最大流]最短路+最大流
2485 Destroying the bus stations    [最大流]最短路+最大流
3468 Treasure Hunting    [最大流](二分匹配)+最短路
3998 Sequence(难)    [DP+最大流]最长上升子序列
4309 Seikimatsu Occult Tonneru    [最大流]枚举状态+最大流
3472 HS BDC    [混合欧拉]
----------------------------------------------------------------------------------------------
1533Going Home(基础)    [费用流]
3488Tour    [费用流]圈
3435A new Graph Game    [费用流]圈
1853Cyclic Tour    [费用流]圈
2686Matrix    [费用流]
3376Matrix Again    [费用流]
3667Transportation    [费用流]拆边
3315My Brute    [费用流](可用KM)
3395Special Fish    [费用流](可用KM匹配)
2448Mining Station on the Sea    [费用流](可用最短路+KM匹配)
4067Random Maze(难)    [费用流]
3947River Problem(难)    [费用流]神奇费用流,流量不等式建图
---------------------------------------------------------------------------------------------
3046Pleasant sheep and big big wolf    [最小割]
1565方格取数(1)    [最小割]
1569方格取数(2)     [最小割]
3820Golden Eggs    [最小割]方格加强
3491Thieves    [最小割]最小点割集
3657Game    [最小割]最大点权独立集
3313Key Vertex    [最小割]
3251Being a Hero    [最小割]
3452 Bonsai    [最小割]一颗带边权的树,最小割求树根和叶子结点不连通
3987 Harry Potter and the Forbidden Forest    [最小割]最小割的情况下,求最少需要割掉多少条边.
2435There is a war    [最小割]打造无敌桥
3917Road constructions    [最大权闭包]最大获利
3879Base Station    [最大权闭包]最大获利
3061Battle    [最大权闭包]最大获利
3996Gold Mine    [最大权闭包]最大获利

4307 Matrix    [最小割]项目分配问题

4265 Science!

4289 Control [最小点权覆盖]

4292 Food

4322 Candy

========================================================================================================
【POJ】
1087A Plug for UNIX     [最大流](可用二分匹配)
1274The Perfect Stall    [最大流](可用二分匹配)
1325Machine Schedule    [最大流](可用二分匹配)
1698Alice's Chance    [最大流](可用二分匹配)
2239Selecting Courses    [最大流](可用二分匹配)
2446Chessboard    [最大流](可用二分匹配) 好题啊
2536Gopher II    [最大流](可用二分匹配)
2771Guardian of Decency    [最大流]二分匹配最大独立集
3041 Asteroids    [最大流](简单二分匹配)
2584 T-Shirt Gumbo    [最大流](多重匹配)
3189 Steady Cow Assignment(中等)    [二分最大流](多重匹配)

1149 PIGS    [最大流] 绝对经典的构图题
1273 Drainage Ditches    [最大流](基础)
1459 Power Network(基础)    [最大流]
3281 Dining    [最大流]
2112 Optimal Milking(基础)    [二分最大流]
2289 Jamie's Contact Groups    [二分最大流]
2391 Ombrophobic Bovines(中等)    [二分最大流]
2455 Secret Milking Machine(基础)    [二分最大流]
3228 Gold Transportation    [二分最大流](并查集)
2699 The Maximum Number of Strong Kings(较难)    [枚举人数 + 最大流]
3498March of the Penguins(中等)    [最大流]枚举汇点,满足点容量限制的网络流
1637 Sightseeing tour(Crazy)    [混合欧拉]
-------------------------------------------------------------------------------------------------------
2135 Farm Tour    [费用流] (来回最短路)
2175Evacuation Plan(中等)    [费用流] 消圈
2195Going Home    [费用流]
2516 Minimum Cost    [费用流]
3422 Kaka's Matrix Travels(中等)    [费用流]拆点
3680 Intervals(较难)    [费用流]经典,费用流+离散化
3686The Windy's    [费用流](KM匹配)

3762 The Bonus Salary!    [费用流]

4406 GPA [费用流]

4411 Arrest [费用流]

-------------------------------------------------------------------------------------------------------
1815 Friendship(中等)    [最小割]最小点割集
1966  Cable TV Network(中等)    [最小割]最小点割集
2125 Destroying The Graph(难)    [最小割]最小点权覆盖
3084 Panic Room(中等,好题)    [最小割]边连通度
3204 Ikki's Story I - Road Reconstruction(基础)    [最小割]求关键边
3308 Paratroopers(较难)    [最小割]乘积取对数,最小点权覆盖
3436ACM Computer Factory    [最小割]收集流,残留搜集找边
3469 Dual Core CPU(中等)    [最小割]项目分配问题
3921Destroying the bus stations    [最小割]点连通
2987 Firing(较难)    [最大权闭包]
3155 Hard Life(很挑战一题)    [最大密度子图]
=============================================================================================

【其他OJ】

LightOJ 上面已经有分类了,所以自己可以再上面找网络流的题目

 

zoj3348Schedule    [最大流]已经比了几场,还有几场没比.问DD能不能取得冠军
zoj2760 How Many Shortest Path    [最大流]不相交最短路径数
zoj3460 Missile    [最大流]按不同时间将每个点拆点,二分时间,判断是否是完美匹配.
zoj3362 Beer Problem    [费用流]最大费用流,每次增广.直到费用归本时,break;
zoj2532 Internship    [最小割]增加哪些边的流量,可以增大最大流.(求关键割边)
ZOJ2587 Unique Attack    [最小割](最小割的唯一性判定)
ZOJ2539 Energy Minimization    [最小割]项目分配问题
ZOJ2071 Technology Trader    [最大权闭包]输出选择方案
ZOJ2332 Gems

SGU326 Perspective (构图题,类似于 WHU 1124) 
SGU438 The Glorious Karlutka River =) (按时间拆点) 
SGU242 Student's Morning (输出一组解) 
SGU185 Two shortest (Dijkstra 预处理,两次增广,必须用邻接阵实现,否则 MLE) 

HOJ2816 Power Line 
HOJ2634 How to earn more
HOJ2811 Earthquake Damage (最小点割集)
HOJ2715 Matrix3
HOJ2739 The Chinese Postman Problem
HOJ2543 Stone IV

WHU1124 Football Coach (构图题) 
JOJ2453 Candy (构图题) 
TJU2944 Mussy Paper (最大权闭合子图) 
BUAA1032 Destroying a Painting
BASHU2445 餐巾问题

SPOJ 839 Optimal Marks (将异或操作转化为对每一位求最小割)
Spoj660:http://www.spoj.pl/problems/QUEST4/
Spoj377:http://www.spoj.pl/problems/TAXI/

[UVA]

753 , 820 , 10330 , 10735

11248 [最大流]先求起点到终点的最大流,然后在残留网络中,求起点到每个点的最大流,以及每个点到终点的最大流.然后枚举每条边增加容量能否满足题意.

 

[TC]:

Single Round Match 200 Round 1 – Division I, Level Three
Single Round Match 236 Round 1 – Division I, Level Three
Single Round Match 399 Round 1 – Division I, Level Three
2003 TCO Semifinal Round 4 – Division I, Level Three
2004 TCCC Championship Round – Division I, Level Three
2005 TCO Sponsor Track Round 3 – Division I, Level One

 

[RQNOJ]

306 破坏石油运输系统问题
338 [NOI08]志愿者招募
529 [NOI09]植物大战僵尸
556 [NOI06]最大获利

606 [NOI2010]海拔

=============================================================================================
【上下界网络流】
ZOJ 2314 可行流
Zoj 3229  最大流
zoj 1994 可行流
Pku 2396 可行流
Hdu3157 最小流
Sgu176 最小流
hust1342 最小流
=============================================================================================
【无向图最小割】
hdu3691
hdu3002
poj2914
poj1966
zoj2753

1.hdu1532

最基础最大流,给出起点,终点,和一些边,求最大流

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int inf = 1000000000;
const int maxn = 20000, maxm = 500000;
struct Edge{
    int v, f, nxt;
};
int src, sink;
int g[maxn+10];
int nume;
Edge e[maxm * 2 +10];
void addedge(int u, int v, int c){
    e[++nume].v = v;
    e[nume].f = c;
    e[nume].nxt = g[u];
    g[u] = nume;
    e[++nume].v = u;
    e[nume].f = 0;
    e[nume].nxt = g[v];
    g[v] = nume;
}
void init(){
    memset(g, 0, sizeof(g));
    nume = 1;
}
queue<int> que;
bool vis[maxn+10];
int dist[maxn + 10];
void bfs(){
    memset(dist, 0, sizeof(dist));
    while(!que.empty()) que.pop();
    vis[src] = true;
    que.push(src);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = g[u]; i; i = e[i].nxt)
        if(e[i].f && !vis[e[i].v]){
            que.push(e[i].v);
            dist[e[i].v] = dist[u] + 1;
            vis[e[i].v] = true;
        }
    }
}
int dfs(int u, int delta){
    if(u == sink){
        return delta;
    }else{
        int ret = 0;
        for(int i = g[u]; delta && i; i = e[i].nxt)
        if(e[i].f && dist[e[i].v] == dist[u]+1){
            int dd = dfs(e[i].v, min(e[i].f, delta));
            e[i].f -= dd;
            e[i^1].f += dd;
            delta -= dd;
            ret += dd;
        }
        return ret;
    }
}
int maxflow(){
    int ret = 0;
    while(true){
        memset(vis, 0, sizeof(vis));
        bfs();
        if(!vis[sink]) return ret;
        ret += dfs(src, inf);
    }
}
int main(){
    int n, m;
    while(scanf("%d%d", &m, &n)!=EOF){
        init();
        for(int i = 0;i < m; i++){
            int u, v, l;
            scanf("%d%d%d", &u, &v, &l);
            addedge(u, v, l);
        }
        src = 1;
        sink = n;
        printf("%d\n", maxflow());
    }
}
View Code

 

2.hdu3549

最基础最大流,套模板就行

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int inf = 1000000000;
const int maxn = 20000, maxm = 500000;
struct Edge{
    int v, f, nxt;
};
int src, sink;
int g[maxn+10];
int nume;
Edge e[maxm * 2 +10];
void addedge(int u, int v, int c){
    e[++nume].v = v;
    e[nume].f = c;
    e[nume].nxt = g[u];
    g[u] = nume;
    e[++nume].v = u;
    e[nume].f = 0;
    e[nume].nxt = g[v];
    g[v] = nume;
}
void init(){
    memset(g, 0, sizeof(g));
    nume = 1;
}
queue<int> que;
bool vis[maxn+10];
int dist[maxn + 10];
void bfs(){
    memset(dist, 0, sizeof(dist));
    while(!que.empty()) que.pop();
    vis[src] = true;
    que.push(src);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = g[u]; i; i = e[i].nxt)
        if(e[i].f && !vis[e[i].v]){
            que.push(e[i].v);
            dist[e[i].v] = dist[u] + 1;
            vis[e[i].v] = true;
        }
    }
}
int dfs(int u, int delta){
    if(u == sink){
        return delta;
    }else{
        int ret = 0;
        for(int i = g[u]; delta && i; i = e[i].nxt)
        if(e[i].f && dist[e[i].v] == dist[u]+1){
            int dd = dfs(e[i].v, min(e[i].f, delta));
            e[i].f -= dd;
            e[i^1].f += dd;
            delta -= dd;
            ret += dd;
        }
        return ret;
    }
}
int maxflow(){
    int ret = 0;
    while(true){
        memset(vis, 0, sizeof(vis));
        bfs();
        if(!vis[sink]) return ret;
        ret += dfs(src, inf);
    }
}
int main(){
    int cas = 1;
    int n, m;
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        init();
        for(int i = 0;i < m; i++){
            int u, v, l;
            scanf("%d%d%d", &u, &v, &l);
            addedge(u, v, l);
        }
        src = 1;
        sink = n;
        printf("Case %d: %d\n", cas++, maxflow());
    }
}
View Code

 

3.hdu3572

题意:有M个机器,有N个任务。每个任务必须在Si 或者以后开始做,在Ei 或者之前完成,完成任务必须处理Pi 个时间单位。其中,每个任务可以在任意(空闲)机器上工作,每个机器的同一时刻只能工作一个任务,每个任务在同一时刻只能被一个机器工作,而且任务做到一半可以打断,拿去其他机器做。问:能否在规定时间内把任务做完。

用一个源点连所有任务,流量是任务需要的天数,每个天数与汇点之间连一条流量是m的边,表示每天只有m台机器工作

用dinic会超时所以用sap

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int n,m;
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){
    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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


int main(){
    int cas = 1;
    int n, m;
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        init();
        int T = 0;
        int sum = 0;
        for(int i = 1; i <= n; i++){                
            int p, s, e;
            scanf("%d%d%d", &p, &s, &e);
            addedge(0, i, p);
            for(int t = s; t <= e; t++){
                addedge(i, t+n, 1);
            }
            T = max(T, e);
            sum += p;
        }

        int src = 0;
        int sink = n+T+1;
        for(int i = 1; i <= T; i++){
            addedge(i+n, sink, m);
        }
        NV = sink+10;                ///注意,比一共有的点数加1
        printf("Case %d: ", cas++);
        int ans = SAP(src, sink);
        //printf("%d\n", ans);
        if(sum == ans)
            printf("Yes\n");
        else
            printf("No\n");
        puts("");
    }
}
View Code

 

4.HDU2732

题意,有n个蜥蜴,每个蜥蜴在一个柱子上,每个柱子同一时间只能有一个蜥蜴,每个蜥蜴每次跳的费曼距离不能超过d,每个柱子允许有固定个蜥蜴踩过,问有多少个蜥蜴能过跳出这个迷宫

建图不难,难在输出格式太容易被坑

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
using namespace std;
#define MAXM 555555
#define MAXN 2222
#define inf 10000
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int n,m;
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){
    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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


char mp[29][23];
char mp2[30][30];
int num[30][30];
int main(){
    int cas = 1;
    int n, m, d;
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &d);
        init();
        memset(mp, 0, sizeof(mp));
        memset(mp2, 0, sizeof(mp2));
        memset(num, 0, sizeof(num));
        for(int i =1; i <= n; i++){
            scanf("%s", mp[i]+1);
        }
        for(int i = 1; i <= n; i++){
            scanf("%s", mp2[i]+1);
        }

        m = strlen(mp[1]+1)+1;
        n++;
        int l = 2;
       // printf("%d == i %d == k\n", n, m);
        for(int i = 1; i< n; i++){
            for(int k = 1; k < m; k++){
                //printf("*%c", mp[i][k]);
                if('1' <= mp[i][k] && mp[i][k] <= '9'){
                   // printf("%d %d\n", i, k);
                    num[i][k] = l++;
                }
            }//puts("");
        }int sum = 0;
        int src = 0;
        int sink = 1;
        NV = l*2 +1;
        for(int i = 0; i <= n; i++){
            for(int k = 0; k <= m; k++){
                if(mp2[i][k] == 'L'){
                    //printf("%d %d\n", i, k);
                    addedge(src, num[i][k], 1);
                    sum ++;
                }
            }
        }
        for(int i = 1; i < n; i++){
            for(int k = 1; k < m; k++){
                if(num[i][k]){
                    addedge(num[i][k], num[i][k] + l, mp[i][k] - '0');
                }
            }
        }
        for(int i = 1; i < n; i++){
            for(int k = 1; k < m; k++){
                if(num[i][k])
                for(int i1 = 0; i1 <= n; i1 ++){
                    for(int k1 = 0; k1 <= m; k1 ++){
                        if(i1 == i && k1 == k) continue;
                        if(abs(i1-i) + abs(k1 - k) <= d)
                        if(mp[i1][k1] == 0){
                            addedge(num[i][k]+l, sink, inf);
                        }else if(num[i1][k1]){
                            addedge(num[i][k] +l, num[i1][k1], inf);
                        }
                    }
                }
            }
        }
        int ans = sum - SAP(src, sink);
        printf("Case #%d: ", cas++);
        //int ans = tot - gao.Maxflow(s, t);
        if (ans == 0) printf("no ");
        else printf("%d ", ans);
        if (ans <= 1) printf("lizard was ");
        else printf("lizards were ");
        printf("left behind.\n");
    }
}
View Code

 

5.HDU3338 Kakuro Extension

 

 

原数谜是个很有趣的游戏,如图,每一行或每一列空白称为一个回,每一回都对应着一个整数sum,sum就是这回的和。这些空白格里只能填入1—9这九个数字,且在每一回中不能重复。全黑色的格为空,有数字的格,左下角的表示列的和,右上角的表示行的和,则可以得到下面这个图。

 

 

 其实每一个必须填的点都只和最多两个点相连,一个是控制行的一个是控制列的,那就用控制行的那些与源点相连,控制列的与汇点相连就好,由于每个点少都是1,其实只要将控制行和列的那些点分别减去控制的点的个数就好,这样建边的时候最大容量是8,输出的时候只要输出这个点连着的反向边(无论是与控制行的点连的还是控制列的点连的)+1就行。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 32222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int ans[105][105];
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

int addedge(int u,int v,int cap,int cc=0){
    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

    edge[NE].cap=cc;edge[NE].v=u;
    edge[NE].next=head[v];head[v]=NE++;
    return NE-1;
}

int n, m;
char str[105][105][10];
int num[105][105];                               //第一维度 1 代表行 2 代表列 3 代表 行加列  4代表需要填数字  0代表啥都没有
int row[105][105], column[105][105];                   //第二维度 0行的值 1 列的值
int id[105][105][3];
int allId;
int src, sink ;
void make(int ii, int kk, char s[]){
    id[ii][kk][0] = allId++;
    if(s[0] == '.'){
        num[ii][kk] = 4;
    }else{
        num[ii][kk] = 0;
        if(s[0] != 'X'){
            id[ii][kk][2] = allId++;
            num[ii][kk] |= 2;
            column[ii][kk] = (s[0]-'0')*100+ (s[1]-'0')*10+s[2]-'0';
        }
        if(s[4] != 'X'){
            id[ii][kk][1] = allId++;
            num[ii][kk] |= 1;
            row[ii][kk] = (s[4] - '0')*100 +(s[5]-'0')*10 + s[6] - '0';
        }
    }
}
void sub_row(int ii, int kk){
    for(int k = kk+1; k < m; k++){
        if(num[ii][k] == 4){
            row[ii][kk] --;
            ans[ii][k] =  addedge(id[ii][kk][1], id[ii][k][0], 8);                     //行到该点
        }else break;
    }
    addedge(src, id[ii][kk][1], row[ii][kk]);                           //起点到行
}
void sub_column(int ii, int kk){
    for(int i = ii+1; i < n; i++){
        if(num[i][kk] == 4){
            ans[i][kk] = addedge(id[i][kk][0], id[ii][kk][2], 8);                    //该点到列

            column[ii][kk] --;
        }else break;
    }
    addedge(id[ii][kk][2], sink, column[ii][kk]);                           //列到终点
}
int main(){
    while(scanf("%d%d", &n, &m)!=EOF){

        init();
        allId = 2;
        src = 0, sink = 1;
        for(int i = 0;i < n; i++){
            for(int k = 0;k < m; k++){
                scanf("%s", str[i][k]);
                make(i, k, str[i][k]);
            }
        }
        for(int i = 0; i < n; i++){
            for(int k = 0;k < m; k++){
                if(num[i][k] & 1){
                    sub_row(i, k);
                }
                if(num[i][k] & 2)
                    sub_column(i, k);
            }
        }
        NV = allId;
        SAP(src, sink);
        for(int i = 0; i < n; i++){
            for(int k = 0;k  < m; k++){
                if(k) printf(" ");
                if(num[i][k] == 4){
                    printf("%d", edge[ans[i][k]].cap+1);
                }else{
                    printf("_");
                }
            }puts("");
        }
    }
}
View Code

 

 6,hdu3605

题意,有一些人要移民,每个人都有一些可以去的星球,但是每个星球都只能去固定的人数,问最多有多少人能够移民

直接裸建图会T掉,所以用每个人能够去的星球去将人分类

 

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int n,m;
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){

    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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

int num[(1<<11) + 100];
int main(){
    int n, m;
    while(scanf("%d%d", &n, &m)!=EOF){          //将所有的点压缩到1~(1<<m) - 1  num 表示这样的人有多少
        init();
        memset(num, 0, sizeof(num));
        for(int i =0;i < n; i++){
            int id = 0;
            for(int k = 0; k < m; k++){
                int x;
                scanf("%d", &x);
                if(x){
                    id += 1<<k;
                }
            }
            num[id] ++;
        }
        for(int i = 0;i < m; i++){
            int x;
            scanf("%d", &x);
            num[(1<<m) + i] = x;                //星球的点变成(1<<m) + i num表示每个星球能够承载的人数
        }
        int src = (1<<m) +m + 1;
        int sink = (1<<m) + m +2;
        NV = sink+1;
        for(int i = 0;i < (1<<m); i++){
            addedge(src, i, num[i]);                //从起点到每种人建立一条人数的边
            for(int k = 0; k < m;k ++){
                if((1<<k) & i){
                    addedge(i,(1<<m) + k, num[i]);          //每种人到对应的每个星球都建立一条人数的边
                }
            }
        }
        for(int i =0 ;i < m; i++){
            addedge(i+(1<<m), sink, num[i+(1<<m)]);     //星球到终点建立一条星球能承载最大人数的边
        }
        //printf("%d\n", SAP(src, sink));
        if(SAP(src, sink) == n) printf("YES\n");
        else printf("NO\n");
    }
}
View Code

 7.hdu4183

题意:有多个点,每个点给出坐标与半径,加入两个点相交,就可以从这两个点走。题目要求先从起点到终点,再从终点回到起点。从起点到终点的过程中,只能从频率小的走到频率大的点(前提是两点相交),从终点到起点的过程中,只能从频率大的走到频率小的。在走的过程中,除了起点与终点,别的只要走过就会消失,就是说只能走一次。问可不可以从起点到终点又回到起点。

从起点到终点的流量是大于等于2就好

注意,起点的频率是400 终点的频率是789 如果两点能直接相连的话算可以走两次

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int n,m;
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){

    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

    edge[NE].cap=cc;edge[NE].v=u;
    edge[NE].next=head[v];head[v]=NE++;
}
const int maxa = 333;
double siz[maxa];
int px[maxa], py[maxa], r[maxa];
int judge(int i, int j){
    if((r[i] + r[j]) * (r[i] + r[j]) >= (px[i] - px[j]) * (px[i] - px[j]) + (py[i] - py[j]) *(py[i] - py[j]))
        return 1;
    return 0;
}
int main(){
    int t, n;
    scanf("%d", &t);
    while(t--){
        init();
        scanf("%d", &n);
        int src, sink;
        for(int i =0 ;i < n; i++){
            scanf("%lf%d%d%d", &siz[i], &px[i], &py[i], &r[i]);
            if(siz[i] == 400.00){
                src = i;
            }
            if(siz[i] == 789.0) sink = i;
        }
        for(int i =0;i < n; i++){
            for(int j = i+1; j < n; j++){
                if(judge(i, j)){
                    if(siz[i] < siz[j])
                        addedge(i, j, 1);
                    else if(siz[i] > siz[j])addedge(j, i, 1);
                }
            }
        }
        NV = n;
        if(SAP(src, sink) >= 2 ||judge(src, sink)){
            printf("Game is VALID\n");
        }else{
            printf("Game is NOT VALID\n");
        }
    }
}
View Code

 

8.hdu3081

这道题的特点在于有m个女孩如果是朋友必定对应同样的m个男孩,所以只要在源点到女孩上建边为mid,男孩到汇点上建边为mid,女孩与能选择的男孩建边为1,如果最大流为mid*n那么就能成立。

也就是说如果每个男还都能连出mid条边的话,就能保证没一句连得都是不同的边

二分mid

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){
   // printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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


const int maxa = 111;
int fa[maxa];
int no_quarreled[maxa][maxa];
int find(int i){
    return fa[i] == i ? i: find(fa[i]);
}
int n, p, q;
int EDGE[maxa][maxa];
int judge(int mid){
    init();
    int s = 0, t = 2*n +1;
    NV = 2*n+2;
    for(int i = 1; i <= n; i++){
        addedge(s, i, mid);
    }
    for(int i = 1; i <= n; i++){
        for(int k =1; k <= n; k++){
            if(EDGE[i][k]) addedge(i, k+n, 1);
        }
    }
    for(int i = 1; i <= n; i++){
        addedge(i+n, t, mid);
    }
    //printf("%d\n", SAP(s, t));
    if(SAP(s, t) == mid * n) return 1;
    else return 0;
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d%d", &n, &p, &q);
        init();
        memset(no_quarreled, 0, sizeof(no_quarreled));
        memset(EDGE, 0, sizeof(EDGE));
        for(int i = 0;i < p; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            no_quarreled[u][v] = 1;
        }
        for(int i = 1; i <= n; i++){
            fa[i] = i;
        }
        for(int i = 0;i  < q; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            fa[find(u)]  = find(v);
        }
            for(int i = 1;i <= n; i++){
        for(int k = 1; k <= n; k++){
            if(no_quarreled[i][k]){
                for(int j = 1; j <= n; j ++){
                    if(find(i) == find(j)){
                        EDGE[j][k] = 1;
                    }
                }
            }
        }
    }

        //judge(2);

        /*for(int i = 1;i <= n; i++){
            printf("%d ", fa[i]);
        }puts("");*/
        int low = 0, high = n+1;
        while(high > low){
            int mid = (high + low) / 2;
            if(judge(mid)) low = mid + 1;
            else high = mid;
        }
        printf("%d\n", low-1);
    }
}
View Code

 

9.hdu3277

题意和上一个一样,只不过每个女孩还可以另外选K个男孩

刚开始想的是直接和上一个题做法一样最后答案为min(n, mid+K)

但是wa了,反例是如果每个女孩都选除了1号男孩以外的所有男孩,那么此时mid是0,但是如果K是1的话相当于所有的女孩和所有的男孩都建立边,此时答案是n

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){
   // printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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


const int maxa = 255;
int fa[maxa];
int no_quarreled[maxa][maxa];
int find(int i){
    return fa[i] == i ? i: find(fa[i]);
}
int n, p, q, K;
int EDGE[maxa][maxa];
int judge(int mid){             //女1 1 -> n 女2 1 n+1 -> n+n, 男 2n+1 -> 3n
    init();
    int s = 0, t = 3*n +1;
    NV = 3*n+2;
    for(int i = 1; i <= n; i++){
        addedge(s, i, mid);
    }
    for(int i = 1; i <= n; i++){
        for(int k =1; k <= n; k++){
            if(EDGE[i][k]) addedge(i, k+2*n, 1);
            else addedge(i+n, k+2*n , 1);
        }
        addedge(i, i+n, K);
    }
    for(int i = 1; i <= n; i++){
        addedge(i+2*n, t, mid);
    }
    //printf("%d\n", SAP(s, t));
    if(SAP(s, t) == mid * n) return 1;
    else return 0;
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d%d%d", &n, &p, &K, &q);
        init();
        memset(no_quarreled, 0, sizeof(no_quarreled));
        memset(EDGE, 0, sizeof(EDGE));
        for(int i = 0;i < p; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            no_quarreled[u][v] = 1;
        }
        for(int i = 1; i <= n; i++){
            fa[i] = i;
        }
        for(int i = 0;i  < q; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            fa[find(u)]  = find(v);
        }
    for(int i = 1;i <= n; i++){
        for(int k = 1; k <= n; k++){
            if(no_quarreled[i][k]){
                for(int j = 1; j <= n; j ++){
                    if(find(i) == find(j)){
                        EDGE[j][k] = 1;
                    }
                }
            }
        }
    }

        //judge(2);

        /*for(int i = 1;i <= n; i++){
            printf("%d ", fa[i]);
        }puts("");*/
        int low = 0, high = n+1;
        while(high > low){
            int mid = (high + low) / 2;
            if(judge(mid)) low = mid + 1;
            else high = mid;
        }
        printf("%d\n", low-1);
    }
}
/*
1
4 3 3 2
3 2
4 2
4 4
1 4
2 3
*/
View Code

 

10.hdu3416

题意,有n个城市,有个人从a城市走到b城市,给出一些路径以及长度,这个人每次只走最短路,且每条路只能走1次,问能最多走多少次。

求最短路,把所有属于最短路上的边建立图,求最大流

#include<vector>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){
    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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


const int maxa = 1005;
vector<int>e[maxa], len[maxa], e1[maxa], len1[maxa];
int vis[maxa];

int t, n, m;
int makeshort(int s, int bell[]){
    memset(vis,0 , sizeof(vis));
    for(int i = 1; i <=n ;i ++){
        bell[i] = 10000000;
    }
    bell[s] = 0;
    memset(vis, 0, sizeof(vis));
    for(int i = 1;i <= n; i++){
        int kk = 1;
        int maxn = 10000000;
        for(int k = 1; k <= n; k++){
            if(vis[k] == 0 && bell[k] < maxn){
                kk = k;
                maxn = bell[k];
            }
        }
        vis[kk] = 1;
        for(int k = 0; k < e[kk].size(); k++){
            int u = e[kk][k];
            bell[u] = min(bell[u], bell[kk] + len[kk][k]);
        }
    }
}
int makeshort1(int s, int bell[]){
    memset(vis,0 , sizeof(vis));
    for(int i = 1; i <=n ;i ++){
        bell[i] = 10000000;
    }
    bell[s] = 0;
    memset(vis, 0, sizeof(vis));
    for(int i = 1;i <= n; i++){
        int kk = 1;
        int maxn = 10000000;
        for(int k = 1; k <= n; k++){
            if(vis[k] == 0 && bell[k] < maxn){
                kk = k;
                maxn = bell[k];
            }
        }
        vis[kk] = 1;
        for(int k = 0; k < e1[kk].size(); k++){
            int u = e1[kk][k];
            bell[u] = min(bell[u], bell[kk] + len1[kk][k]);
        }
    }
}
int ed[100005][3];
int main(){
    scanf("%d", &t);
    while(t--){
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1;i <= n; i++){
            e[i].clear();
            len[i].clear();
            e1[i].clear();
            len1[i].clear();
        }
        for(int i = 0;i < m; i++){
            int u, v, d;
            scanf("%d%d%d", &u, &v, &d);
            ed[i][0] = u, ed[i][1] = v, ed[i][2] = d;
            e[u].push_back(v);
            len[u].push_back(d);
            e1[v].push_back(u);
            len1[v].push_back(d);
        }
        int s, t;
        scanf("%d%d", &s, &t);
        int bell1[maxa], bell2[maxa];
        makeshort(s, bell1);
        makeshort1(t, bell2);
        for(int k = 0; k < m; k++){
            int i = ed[k][0], u = ed[k][1];
            if(bell1[i] + ed[k][2] + bell2[u] == bell1[t]){
                addedge(i, u, 1);
            }
        }
        NV = n+1;
        printf("%d\n", SAP(s, t));
    }
}
View Code

 

11.hdu3468

题意::iSea和他的朋友一块去寻宝,地图上显示了很多的金币,图中有字母'A', 'B' ... 'Z', 'a', 'b' ... 'z',表示他们每次的会合地点,开始位置在A,他朋友每次以最短的距离有一个会合地点走向下一个会合地点,iSea也必须走最短路,但是他可以选择走有 金币的路,不过他只有一个单位的时间可以拿到金币,也就是说,每一次的会合过程,他只能带走一块金币。问:走到最后的会合地点,iSea最多能获得多少金 币。

求出所有A-B,B-C这样的路径上有金币的点,每条路径作为一个点,与金币这个点连一条路径为1的点,在二分图最大匹配就好

我用网络流做的,思路是一样的,点的数组开小了,卡了两个多小时,最后知道真相的我眼泪掉下来。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 22222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int n,m;
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){
    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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

const int maxa = 105;
char mp[maxa][maxa];
int loca_p[maxa][2];
int num[maxa][maxa];
int r, c;
void make(int r, int c, int &num_p){
    for(int i = 0;i < r; i++){
        for(int k = 0; k < c; k++){
            int id = -1;
            if('a' <= mp[i][k] && mp[i][k] <= 'z'){
                id = mp[i][k] - 'a' + 26;
            }
            if('A' <= mp[i][k] && mp[i][k] <= 'Z')
                id = mp[i][k] - 'A';
            if(id != -1){
                num_p = max(num_p, id);
                loca_p[id][0] = i;
                loca_p[id][1] = k;
                addedge(0, num[i][k], 1);
            }
        }
    }
}
struct point{
    int x, y;
    point(int xx, int yy):x(xx), y(yy){}
};
bool judge(int vis[maxa][maxa], int x, int y){
    if(mp[x][y] != '#' && vis[x][y] == -1 && 0 <= x && x < r && 0 <= y && y < c){
        return 1;
    }else return 0;
}
int Move[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
void bfs(int s, int t, int vis[maxa][maxa]){
    //printf("lalala\n");
    for(int i = 0; i < r; i++){
        for(int k = 0; k < c; k++){
            vis[i][k] = -1;
        }
    }
    vis[loca_p[s][0]][loca_p[s][1]] = 0;
    queue<point> Q;
    while(!Q.empty()) Q.pop();
    Q.push(point(loca_p[s][0], loca_p[s][1]));
    while(!Q.empty()){
        int x = Q.front().x, y = Q.front().y;; Q.pop();
        for(int i = 0; i < 4; i++){
            int next_x = x + Move[i][0];
            int next_y = y + Move[i][1];
            if(judge(vis, next_x, next_y)){
                vis[next_x][next_y] = vis[x][y] + 1;
                Q.push(point(next_x, next_y));
            }
        }
    }
}

int viss[maxa][maxa], vist[maxa][maxa];
int make_edge(int s, int t){
    bfs(s, t, viss);
    bfs(t, s, vist);
    if(viss[loca_p[t][0]][loca_p[t][1]] == -1) return 0;
    for(int i =0 ;i < r; i++){
        for(int k = 0; k < c; k++){
            if(mp[i][k] == '*' && vist[i][k] != -1 &&viss[i][k] != -1){
                if(viss[i][k] + vist[i][k] == viss[loca_p[t][0]][loca_p[t][1]]){
                    addedge(num[loca_p[s][0]][loca_p[s][1]], num[i][k], 1);

                }
            }
        }
    }

    return 1;
}

int main(){
    while(scanf("%d%d", &r, &c)!=EOF){
        init();
        memset(loca_p, -1, sizeof(loca_p));
        int s = 0, t = 1;
        for(int i = 0; i < r; i++){
            scanf("%s", mp[i]);
        }
        int num_treasure = 2;
        for(int i = 0;i < r; i++){
            for(int k = 0; k < c; k++){
                num[i][k] = num_treasure++;
            }
        }
        NV = num_treasure;
        int num_p = 0;
        make(r, c, num_p);
        int ok = 0;
        for(int i = 0; i < num_p; i++){
            if(!make_edge(i, i+1)) ok = 1;
        }
        for(int i = 0; i < r; i++){
            for(int k = 0;k < c; k++){
                if(mp[i][k] =='*')
                    addedge(num[i][k], t, 1);
            }
        }
        if(ok){
            printf("-1\n");
        }else{
            printf("%d\n", SAP(s, t));
        }
    }
}
View Code

 

12.hdu3998

题意:给一个数列,求最长上升子序列的长度S,以及最多有多少个不相交的长度为S的子序列

由于每个点只能被用一次,所以需要拆点,按到当前点的最长升序长度分层,层与层之间建边,刚开始忘记了拆点,但这题数据太水居然过了

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int n,m;
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){
    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

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


const int maxa = 1005;
int a[maxa];
int len[maxa];
int main(){
    int n;
    while(scanf("%d", &n)!=EOF){
        init();
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        int max_len = 0;
        for(int i = 1;i <= n; i++){
            len[i] = 1;
            for(int k = 1; k < i; k++){
                if(a[i] > a[k]){
                    len[i] = max(len[i], len[k]+1);
                }
            }
            max_len = max(max_len, len[i]);
        }
        int s = 0, t = 2*n+1;
        NV = n*2+2;
        for(int i = 1; i <= n; i++){
            addedge(i, i+n, 1);
            if(len[i] == 1){
                addedge(s, i, 1);
            }
            if(len[i] == max_len){
                addedge(i+n, t, 1);
            }
            for(int k = 1; k < i; k++){
                if(len[i] == len[k]+1){
                    addedge(k+n, i, 1);
                }
            }
        }
        printf("%d\n%d\n", max_len, SAP(s, t));
    }
}
View Code

 

转载于:https://www.cnblogs.com/icodefive/p/4810613.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值