看到这种题目,一般就是想到构建网络流,然后一种割对应一种方案(本题中为割完后S和选文科的相连,T和选理科的项链),求最小割把。。
考虑一个点x(代表一个同学),如果选文科,就要和T割断(理科割S),割断的为损失的部分,即选理科的喜悦值,因此连边x->T,容量为选理科的喜悦值;同理连边S->x,容量为选文科的喜悦值。
然后考虑两个相邻的点x,y,不同的方案对答案产生的影响。设u为x,y都选文科的额外喜悦值;v为x,y都选理科的额外喜悦值,flow(p,q)表示从p到q连容量为flow(p,q)的边(不包括前面已经连好的边)。那么有三种情况:
1.x,y都选文科,那么需要将x和y到T的边的割断,各自损失的喜悦值已经减去了,那么还需要减去损失的都选理科的喜悦值。即flow(x,T)+flow(y,T)=v;
2.x,y都选理科,同上分析可得,flow(S,x)+flow(S,y)=u;
3.x,y一个选文科一个选理科,不妨设x选文科。那么显然都选文和都选理的额外喜悦值都损失了。这时我们发现前面两条已经把S->x,y和x,y->T的边都建好了,不能改动(否则上面就出问题了)。因此考虑在x->y或者y->x中连边。那么由于割完后S和x相连,y与T相连,那么如果有一条x->y的边,则必须要将这条边割断,因此在x->y的边上做文章。因此得到flow(S,x)+flow(x,y)+flow(y,T)=u+v;同理得到flow(S,y)+flow(y,x)+flow(x,T)=u+v。
然后就发现这需要flow(S,x)=flow(S,y)=u/2,flow(x,T)=flow(y,T)=v/2,flow(x,y)=flow(y,x)=(u+v)/2即可。那么这些边再加上前面的边就是完整的建图了。操作时把起点和终点相同的边合并可以加快速度。
AC代码如下:
#include
#include
#include
#define N 100005
#define inf 1000000000
using namespace std;
int n,m,tot=1,gol,a[6][105][105],fst[N],pnt[N],len[N],nxt[N],d[N],h[N];
int pt(int x,int y){ return (x-1)*n+y; }
void add(int x,int y,int z){
pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot;
}
void ins(int x,int y,int z,int p){ add(x,y,z); add(y,x,z*p); }
bool bfs(){
int head=0,tail=1; h[1]=0;
memset(d,-1,sizeof(d)); d[0]=1;
while (head3) y--; else if (k>1) x--;
for (i=1; i<=x; i++)
for (j=1; j<=y; j++){
scanf("%d",&a[k][i][j]); sum+=a[k][i][j];
}
}
gol=m*n+1;
for (i=1; i<=m; i++)
for (j=1; j<=n; j++){
ins(0,pt(i,j),(a[0][i][j]<<1)+a[2][i][j]+a[2][i-1][j]+a[4][i][j]+a[4][i][j-1],0);
ins(pt(i,j),gol,(a[1][i][j]<<1)+a[3][i][j]+a[3][i-1][j]+a[5][i][j]+a[5][i][j-1],0);
if (i>1));
return 0;
}
by lych
2016.3.11