【bzoj1001】[BeiJing2006]狼抓兔子
*题目描述:
现在小朋友们最喜欢的”喜羊羊与灰太狼”,话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
左上角点为(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
*/
题外话:这里是我写的两种方法的运行时间比较:
因为是网格图,所以SPFA跑得很慢,然而我蒟蒻还不(lan)会(de)写堆优化dij,所以这对偶了是等于没有对偶╮(╯▽╰)╭