这两道题目除了数据大小不同外是一模一样的
题目大意是给定一个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; }