[关键字]:图论 网络流
[题目大意]:太麻烦,不写了……
//==================================================================================================
[分析]:先说80分的思路,其实所有点的海拔不是0就是1,因为可以通过修改让所有非0或1的海拔降低一定回减少费用。所以要求的就是在原图以左上为源以右下为汇求一个最小割。一开始无缘无故的WA,后来发现它输入的顺序是以y为第一关键字x为第二关键字,我写反了……在N天以后,终于搞定了AC解法。因为是平面图,所以可以转化成当前图的对偶图来做。所谓对偶图就是将平面图中的面变成点,而原来在这两个面之间的边作为新图这两个点之间的边,这样每走过一条边就相当于切断原来的这条边,所以一条从源到汇的最短路经就代表了一个最小割。对于此图而言0和1的分界线一定是如下图所示,因为每一个孤立的0或1都可以同过修改来减小,所以对于新图,就是求一条从左下到右上(反过来一样,我是反过来走的)的最短路(最小割)。
因为两个面之间是两条边搜以连那个边要仔细斟酌,如下图
还有其他的一些小细节,就不在一一说了,详见代码
[代码]:
80分
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=5000000;
const int INF=0x7fffffff;
struct node
{
int y,d;
node *next,*op;
}e[MAXN];
node *first[MAXN];
int N,S,T,n,tot;
int h[MAXN],num[MAXN];
void Add(int x,int y,int d)
{
tot++;
e[tot].y=y;
e[tot].d=d;
e[tot].next=first[x];
e[tot].op=e+tot+1;
first[x]=e+tot;
tot++;
e[tot].y=x;
e[tot].d=0;
e[tot].next=first[y];
e[tot].op=e+tot-1;
first[y]=e+tot;
}
void Init()
{
scanf("%d",&n);
int x,z;
for (int i=1;i<=n+1;i++)
for (int j=1;j<=n;j++)
{
scanf("%d",&z);
x=(i-1)*(n+1)+j;
Add(x,x+1,z);
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n+1;j++)
{
scanf("%d",&z);
x=(i-1)*(n+1)+j;
Add(x,x+(n+1),z);
}
for (int i=1;i<=n+1;i++)
for (int j=2;j<=n+1;j++)
{
scanf("%d",&z);
x=(i-1)*(n+1)+j;
Add(x,x-1,z);
}
for (int i=2;i<=n+1;i++)
for (int j=1;j<=n+1;j++)
{
scanf("%d",&z);
x=(i-1)*(n+1)+j;
Add(x,x-(n+1),z);
}
N=(n+1)*(n+1);
}
int Min(int a,int b)
{
return a<b?a:b;
}
int aug(int u,int flow)
{
if (u==T) return flow;
int l=flow,tmp=N-1;
for (node *p=first[u];p;p=p->next)
{
if (h[u]==h[p->y]+1 && p->d)
{
int f=aug(p->y,Min(l,p->d));
l-=f;
p->d-=f;
p->op->d+=f;
if (l==0 || h[S]==N) return flow-l;
}
if (p->d>0 && tmp>h[p->y]) tmp=h[p->y];
}
if (l==flow)
{
num[h[u]]--;
if (num[h[u]]==0) h[S]=N;
else
{
h[u]=tmp+1;
num[h[u]]++;
}
}
return flow-l;
}
void SAP()
{
int ans=0;
memset(h,0,sizeof(h));
memset(num,0,sizeof(num));
S=1,T=N;
num[0]=N;
while (h[S]<N) ans+=aug(S,INF);
printf("%d\n",ans);
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
Init();
SAP();
return 0;
}
100分
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=5000000;
const int INF=0x7fffffff;
struct node
{
int y,next,d;
}e[MAXN];
struct rec
{
int dat,p;
}heap[MAXN];
int first[MAXN];
int d[MAXN],b[MAXN];
int n,tot,S,T;
void Add(int x,int y,int d)
{
e[++tot].y=y;
e[tot].d=d;
e[tot].next=first[x];
first[x]=tot;
}
int Find(int x,int y)
{
return ((x-1)*n+y);
}
void Init()
{
scanf("%d",&n);
int x;
S=n*n+1,T=n*n+2;
for (int i=1;i<=n;++i)
{
scanf("%d",&x);
Add(S,Find(1,i),x);
}
for (int i=1;i<n;++i)
for (int j=1;j<=n;++j)
{
scanf("%d",&x);
Add(Find(i,j),Find(i+1,j),x);
}
for (int i=1;i<=n;++i)
{
scanf("%d",&x);
Add(Find(n,i),T,x);
}
//===========================================
for (int i=1;i<=n;++i)
{
scanf("%d",&x);
Add(Find(i,1),T,x);
for (int j=2;j<=n;++j)
{
scanf("%d",&x);
Add(Find(i,j),Find(i,j-1),x);
}
scanf("%d",&x);
Add(S,Find(i,n),x);
}
//===========================================
for (int i=1;i<=n;++i)
scanf("%d",&x);
for (int i=1;i<n;++i)
for (int j=1;j<=n;++j)
{
scanf("%d",&x);
Add(Find(i+1,j),Find(i,j),x);
}
for (int i=1;i<=n;++i) scanf("%d",&x);
//=============================================
for (int i=1;i<=n;++i)
{
scanf("%d",&x);
for (int j=2;j<=n;++j)
{
scanf("%d",&x);
Add(Find(i,j-1),Find(i,j),x);
}
scanf("%d",&x);
}
}
void SWAP(int x,int y)
{
b[heap[x].p]=y;
b[heap[y].p]=x;
swap(heap[x],heap[y]);
}
void heap_up(int x)
{
while (x/2>=1)
{
if (heap[x/2].dat>heap[x].dat) SWAP(x/2,x); else break;
x/=2;
}
}
void heap_down(int p)
{
int x=1;
while (x*2<=p)
{
x*=2;
if (x+1<=p && heap[x+1].dat<heap[x].dat) ++x;
if (heap[x/2].dat>heap[x].dat) SWAP(x/2,x); else break;
}
}
void Dij()
{
n=n*n+2;
int x;
for (int i=1;i<=n;++i)
{
d[i]=heap[i].dat=INF;
b[i]=heap[i].p=i;
}
d[S]=heap[S].dat=0;
heap_up(b[S]);
for (int i=1;i<n;++i)
{
x=heap[1].p;
SWAP(1,n-i+1);
heap_down(n-i);
for (int j=first[x];j;j=e[j].next)
{
int y=e[j].y;
if (d[x]+e[j].d<d[y] && b[y]<=n-i)
{
d[y]=d[x]+e[j].d;
heap[b[y]].dat=d[y];
heap_up(b[y]);
}
}
}
printf("%d\n",d[T]);
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
Init();
Dij();
return 0;
}