【bzoj1001】[BeiJing2006]狼抓兔子

*题目描述:
现在小朋友们最喜欢的”喜羊羊与灰太狼”,话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

bzoj1001

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路
1:(x,y)<==>(x+1,y)
2:(x,y)<==>(x,y+1)
3:(x,y)<==>(x+1,y+1)
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.
*输入:
第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输入文件保证不超过10M
*输出:
输出一个整数,表示参与伏击的狼的最小数量.
*样例输入:
3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6
*样例输出:
14
*题解:
SPFA跑不过Dinic系列。。。这题有两种做法,第一种直接依题意建图用Dinic跑最大流(题意就是要求一个最小割,然后用最大流来解决)。第二种就是把平面图的最小割对偶成最短路。把每一个三角形的区域看成是一个点,每一条原图的边看成是分割两个区域的边,然后题目就转化为了从左下到右上的最短距离,用最短路来解决。
*代码:
2016.02.23 *1 Dinic

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

#ifdef WIN32
    #define LL "%I64d"
#else
    #define LL "%lld"
#endif

#ifdef CT
    #define debug(...) printf(__VA_ARGS__)
#else
    #define debug(...)
#endif

#define R register
#define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
#define gmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define gmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1<<15],*S=B,*T=B;
inline int FastIn()
{
    R char ch;R int cnt=0;R bool minus=0;
    while (ch=getc(),(ch < '0' || ch > '9') && ch != '-') ;
    ch == '-' ?minus=1:cnt=ch-'0';
    while (ch=getc(),ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
    return minus?-cnt:cnt;
}
#define maxn 1000010
#define maxm 6000010
#define INF 233333333
int w[maxm],last[maxn],to[maxm],next[maxm],ecnt,ans,dep[maxn],s,t;
int q[maxn];
bool vis[maxn];
#define add(_a,_b,_v) (to[++ecnt]=(_b),next[ecnt]=last[_a],last[_a]=ecnt,w[ecnt]=(_v))
inline bool bfs(){
    memset(dep,-1,sizeof(dep));dep[t]=0;
    R int head=0,tail=1;q[1]=t;
    while (head<tail){
        head++;R int now=q[head];
        for (R int i=last[now];i;i=next[i]){
            R int pre=to[i];
            if (w[i^1]&&dep[pre]==-1){dep[pre]=dep[now]+1;q[++tail]=pre;}
        }
    }
    return dep[s]!=-1;
}
int dfs(R int x,R int f){
    if (x==t) return f;
    R int v,used=0;
    for (R int i=last[x];i;i=next[i]){
        R int pre=to[i];
        if (w[i]&&(dep[x]==dep[pre]+1)){
            R int v=dfs(pre,gmin(f-used,w[i]));
            w[i]-=v;
            w[i^1]+=v;
            used+=v;
            if (used==f) return used;
        }
    }
    if (!used) dep[x]=-1;
    return used;
}
inline void dinic(){
    while (bfs()) {ans+=dfs(s,INF);}
}
int main()
{
    R int n=FastIn(),m=FastIn();s=1;t=n*m;ecnt=1;
    for (R int i=0;i<n;i++)
        for (R int j=1;j<m;j++){
            R int a=i*m+j,b=a+1,v=FastIn();
            add(a,b,v);add(b,a,v);
        }
    for (R int i=0;i<n-1;i++)
        for (R int j=1;j<=m;j++){
            R int a=i*m+j,b=a+m,v=FastIn();
            add(a,b,v);add(b,a,v);
        }
    for (R int i=0;i<n-1;i++)
        for (R int j=1;j<m;j++){
            R int a=i*m+j,b=a+m+1,v=FastIn();
            add(a,b,v);add(b,a,v);
        }
    dinic();
    printf("%d\n",ans );
    return 0;
}

2016.05.17 *1 spfa

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>

#ifdef WIN32
    #define LL "%I64d"
#else
    #define LL "%lld"
#endif

#ifdef CT
    #define debug(...) printf(__VA_ARGS__)
    #define setfile() 
#else
    #define debug(...)
    #define filename ""
    #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif

#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
    R char ch; R int cnt = 0; R bool minus = 0;
    while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
    ch == '-' ? minus = 1 : cnt = ch - '0';
    while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
    return minus ? -cnt : cnt;
}
#define maxx 1010
#define maxn 2000010
#define maxm 10000010
int id[maxx][maxx][2];
struct Edge
{
    Edge *next;
    int to, w;
}*last[maxn], e[maxm], *ecnt = e;
inline void link(R int a, R int b, R int w)
{
    *++ecnt = (Edge) {last[a], b, w}; last[a] = ecnt;
    *++ecnt = (Edge) {last[b], a, w}; last[b] = ecnt;
}
int d[maxn];
bool vis[maxn];
std::queue <int> q;
#define inf 0x7fffffff
int main()
{
//  setfile();
    R int n = FastIn(), m = FastIn(), cnt = 0;
    if (!n || !m) return !printf("0\n");
    if (n == 1 || m == 1)
    {
        R int minn = inf;
        if (m == 1) m = n, n = 1;
        for (R int i = 1; i < m; ++i)
        {
            R int val = FastIn();
            cmin(minn, val);
        }
        return !printf("%d\n", minn == inf ? 0 : minn );
    }
    for (R int i = 1; i < n; ++i)
        for (R int k = 0; k <= 1; ++k)
            for (R int j = 1; j < m; ++j)
                id[i][j][k] = ++cnt;
    R int s = 0, t = ++cnt;
    for (R int i = 1; i <= n; ++i)
    {
        if (i == 1)
            for (R int j = 1; j < m; ++j)
                link(id[i][j][0], t, FastIn());
        else if (i == n)
            for (R int j = 1; j < m; ++j)
                link(s, id[i - 1][j][1], FastIn());
        else
            for (R int j = 1; j < m; ++j)
                link(id[i - 1][j][1], id[i][j][0], FastIn());
    }
    for (R int i = 1; i < n; ++i)
    {
        link(s, id[i][1][1], FastIn());
        for (R int j = 2; j < m; ++j)
            link(id[i][j - 1][0], id[i][j][1], FastIn());
        link(id[i][m - 1][0], t, FastIn());
    }
    for (R int i = 1; i < n; ++i)
        for (R int j = 1; j < m; ++j)
            link(id[i][j][0], id[i][j][1], FastIn());
    q.push(s);
    memset(d, 63, sizeof(d));
    d[s] = 0;
    while (!q.empty())
    {
        R int now = q.front(); q.pop(); vis[now] = 0;
        for (R Edge *iter = last[now]; iter; iter = iter -> next)
        {
            R int pre = iter -> to;
            if (d[pre] > d[now] + iter -> w)
            {
                d[pre] = d[now] + iter -> w;
                if (!vis[pre])
                {
                    q.push(pre);
                    vis[pre] = 1;
                }
            }
        }
    }
    printf("%d\n", d[t] );
    return 0;
}
/*
3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6
*/

题外话:这里是我写的两种方法的运行时间比较:
2016.02.23
2016.05.17
因为是网格图,所以SPFA跑得很慢,然而我蒟蒻还不(lan)会(de)写堆优化dij,所以这对偶了是等于没有对偶╮(╯▽╰)╭

 

posted @ 2016-05-17 14:54  cot  阅读(164)  评论(0编辑  收藏  举报