这两道题目除了数据大小不同外是一模一样的
题目大意是给定一个n*n的矩阵,yifenfei从起点(1, 1)这个位置一直取数到(n,n),每取完一个数,下一个只能取当前数右方或者下方的一个数,(注意两个数之间的距离应该是1,之前以为下方或者右方任何一个数都可以取),就这样取到(n,n),然后再从(n,n)取回(1,1),这次每取完一个数,下一个只能取当前数左方或者右方的一个数,最后回到(1,1),每个数只能被取一次,求这样进行取数之后能取到的最大数
这题可用最大费用最大流来求解,由于每个数只能取一次,所以对当前每一个数要进行拆点,将i拆为i和i'',然后从i连接一条边到i'',容量为1,费用为第i个点的费用,然后将i和取完i点后能取的数连一条边,容量为1,费用为0。因为是从(1,1)->(n,n)->(1,1),所以我们建立超级源点S,连接S和第一个节点,容量为2(因为要走两条路径),费用为0,建立超级汇点T,连接点(n*n)'' 到T,容量为1,费用为0,然后求一次最大费用最大流,因为1和n*n这两个点算了两次,故需要减去一次他们的费用之和,发现网络流的题目数组的大小很重要,之前因为数组问题出现了各种错误,望今后引起高度重视
注:此为3376代码
#include <iostream>
using namespace std;
const int MAXN = 610*610*2+2;
const int MAXM = 4*MAXN;
const int inf = 1<<28;
struct node
{
int from, to, next, value, cost;
}mapp[MAXM];
int id;//记录当前节点标号
int ffa[MAXN];//记录当前节点边
void init()
{
id = 0;
memset(ffa, -1, sizeof(ffa));
}
void addedge(int u, int v, int w, int c)
{
mapp[id].from = u, mapp[id].to = v, mapp[id].value = w, mapp[id].cost = c, mapp[id].next = ffa[u], ffa[u] = id ++;
mapp[id].from = v, mapp[id].to = u, mapp[id].value = 0, mapp[id].cost = -c, mapp[id].next = ffa[v], ffa[v] = id ++;
}
int pre[MAXN];//记录当前最小花费路径
int pos[MAXN];//记录当前最短路径中 的节点标号
int inque[MAXN];
int dist[MAXN];//记录单源最短路径
int que[10*MAXM];
bool SPFA(int s, int e, int n)
{
memset(pre, -1, sizeof(pre));
memset(inque, false, sizeof(inque));
for (int i = 0; i <= n; i ++){
dist[i] = -inf;
}
dist[s] = 0;
int rear, front;
rear = front = 0;
que[rear ++] = s;
inque[s] = true;
pre[s] = s;//
while (front < rear){
int pr = que[front ++];
inque[pr] = false;
for (int i = ffa[pr]; i != -1; i = mapp[i].next){
int fro = mapp[i].from, to = mapp[i].to;
if (mapp[i].value > 0 && dist[to] < dist[fro] + mapp[i].cost){
dist[to] = dist[fro] + mapp[i].cost;
pre[to] = fro, pos[to] = i;
if (!inque[to]){//
que[rear ++] = to;
inque[to] = true;
}
}
}
}
return (pre[e] != -1 && dist[e] > -inf);
}
int flow, cost;
int minCostflow(int s, int e, int n)
{
flow = cost = 0;
while (SPFA(s, e, n)){
int min_flow = INT_MAX;
for (int i = e; i != s; i = pre[i]){//找到当前路径中的瓶颈流量
if (min_flow > mapp[pos[i]].value){
min_flow = mapp[pos[i]].value;
}
}
if (!min_flow)continue;
flow += min_flow;
cost += dist[e];
for (int i = e; i != s; i = pre[i]){
mapp[pos[i]].value -= min_flow;
mapp[pos[i]^1].value += min_flow;
}
}
return cost;
}
void pri(int n)
{
for (int i = 1; i <= n; i ++){
cout<<"i:"<<i<<endl;
for (int j = ffa[i]; j != -1; j = mapp[j].next){
if (mapp[j].value)
cout<<mapp[j].to<<' '<<mapp[j].value<<' '<<mapp[j].cost<<endl;
}
}
}
const int Go[2][2] = {{1, 0}, {0, 1}};
int n;
bool check(int x,int y)
{
return (x > 0 && x <= n && y > 0 && y <= n);
}
int mat[610][610];
int num[MAXN];
int main()
{
//freopen("IN.txt", "r", stdin);
//freopen("OUT.txt", "w", stdout);
while (scanf("%d", &n) != EOF){
init();
int kao = 1;
for (int i = 1; i <= n; i ++){
for (int j = 1; j <= n; j ++){
scanf("%d", &mat[i][j]);
num[kao ++] = mat[i][j];
}
}
/*for (int i = 1; i <= n*n; i ++){
cout<<num[i]<<' ';
}
cout<<endl;*/
for (int i = 1; i <= n*n; i ++){
if (i == 1)addedge(i, i + n*n, 2, num[i]);
else if (i == n*n) addedge(i, i + n*n, 2, num[i]);
else addedge(i, i + n*n, 1, num[i]);
}
for (int i = 1; i <= n; i ++){
for (int j = 1; j <= n; j ++){
//cout<<"j:"<<j<<endl;
for (int k = 0; k < 2; k ++){
//for (int l = 1; l <= n; l ++){
int xx = i + Go[k][0];
int yy = j + Go[k][1];
if (!check(xx, yy))continue;
//cout<<"("<<i<<","<<j<<")->("<<xx<<","<<yy<<")"<<endl;
addedge((i-1)*n + j + n*n, (xx-1)*n + yy, 1, 0);
//}
}
}
}
//pri(2*n*n+2);
int s = 2*n*n + 1, t = 2*n*n + 2;
addedge(s, 1, 2, 0);
addedge(2*n*n, t, 2, 0);
//
printf("%d\n", minCostflow(s, t, 2*n*n+2)-(mat[1][1]+mat[n][n]));
}
return 0;
}