题意:
给一个矩形,从左上角走到右下角,并返回左上角(一个单元格只能走一次,左上角和右下角两个点除外)
并且从左上到右下只能往右和下两个方向。从右下返回左上只能走上和左两个方向!
分析:
拆点,最小费用最大流
。。
额。。。刘汝佳训练指南的最小费用最大流模板超时了。。。。。。。。。。。。。。。。。。
可能是因为边太少,点太多的缘故吧!还是数组实现的邻接表可靠啊!!!
// File Name: 3376.cpp // Author: Zlbing // Created Time: 2013年08月15日 星期四 13时24分37秒 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) /* const int MAXN=720010; struct Edge{ int from,to,cap,flow,cost; }; struct MCMF{ int n,m,s,t; vector<Edge>edges; vector<int> G[MAXN]; int inq[MAXN]; int d[MAXN]; int p[MAXN]; int a[MAXN]; void init(int n){ this->n=n; for(int i=0;i<=n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap,int cost){ Edge e; e.from=from,e.to=to,e.cap=cap,e.flow=0,e.cost=cost; edges.push_back(e); //edges.push_back((Edge){from,to,cap,0,cost}); e.from=to,e.to=from,e.cap=0,e.flow=0,e.cost=-cost; //edges.push_back((Edge){to,from,0,0,-cost}); edges.push_back(e); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s,int t,int& flow,int& cost){ for(int i=0;i<=n;i++)d[i]=INF; CL(inq,0); d[s]=0;inq[s]=1;p[s]=0;a[s]=INF; queue<int>Q; Q.push(s); while(!Q.empty()){ int u=Q.front();Q.pop(); inq[u]=0; for(int i=0;i<(int)G[u].size();i++){ Edge& e=edges[G[u][i]]; if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){ d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]){ Q.push(e.to); inq[e.to]=1; } } } } if(d[t]==INF)return false; flow+=a[t]; cost+=d[t]*a[t]; int u=t; while(u!=s){ edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; u=edges[p[u]].from; } return true; } int Mincost(int s,int t){ int flow=0,cost=0; while(BellmanFord(s,t,flow,cost)); return cost; } }; MCMF solver; */ int sumFlow; const int MAXN = 720010; const int MAXM = 1000010; struct Edge { int u, v, cap, cost; int next; }edge[MAXM<<2]; int NE; int head[MAXN], dist[MAXN], pp[MAXN]; bool vis[MAXN]; void init() { NE = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost; edge[NE].next = head[u]; head[u] = NE++; edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost; edge[NE].next = head[v]; head[v] = NE++; } bool SPFA(int s, int t, int n) { int i, u, v; queue <int> qu; memset(vis,false,sizeof(vis)); memset(pp,-1,sizeof(pp)); for(i = 0; i <= n; i++) dist[i] = INF; vis[s] = true; dist[s] = 0; qu.push(s); while(!qu.empty()) { u = qu.front(); qu.pop(); vis[u] = false; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].cap && dist[v] > dist[u] + edge[i].cost) { dist[v] = dist[u] + edge[i].cost; pp[v] = i; if(!vis[v]) { qu.push(v); vis[v] = true; } } } } if(dist[t] == INF) return false; return true; } int MCMF(int s, int t, int n) // minCostMaxFlow { int flow = 0; // 总流量 int i, minflow, mincost; mincost = 0; while(SPFA(s, t, n)) { minflow = INF + 1; for(i = pp[t]; i != -1; i = pp[edge[i].u]) if(edge[i].cap < minflow) minflow = edge[i].cap; flow += minflow; for(i = pp[t]; i != -1; i = pp[edge[i].u]) { edge[i].cap -= minflow; edge[i^1].cap += minflow; } mincost += dist[t] * minflow; } sumFlow = flow; // 题目需要流量,用于判断 return mincost; } int main() { int n; while(~scanf("%d",&n)) { //solver.init(n*n*2+5); init(); int a; int s=0; int t=((n-1)*n+n-1)*2+1; REP(i,0,n-1) REP(j,0,n-1){ scanf("%d",&a); //solver.AddEdge((i*n+j)*2,(i*n+j)*2+1,1,-a); addedge((i*n+j)*2,(i*n+j)*2+1,1,-a); if(i!=n-1) { //solver.AddEdge((i*n+j)*2+1,((i+1)*n+j)*2,1,0); addedge((i*n+j)*2+1,((i+1)*n+j)*2,1,0); } if(j!=n-1) { //solver.AddEdge((i*n+j)*2+1,(i*n+j+1)*2,1,0); addedge((i*n+j)*2+1,(i*n+j+1)*2,1,0); } } addedge(s,s+1,1,0); addedge(t-1,t,1,0); int ans=-MCMF(s,t,t); printf("%d ",ans); } return 0; }