题意:花最小的费用进行删边操作使图变为欧拉路
题解:模仿混合图欧拉路的构图方法,不过TLE了,看了网上说是SPFA问题,现在还没理解,换了种构图(看其他大牛的博客),
根据a和b的值,在分a>=b 和a<b 两种情况,贪心的策略,考虑保留和取消,在保留的边上对边的度进行调整,删去的边不考虑(因为这个调了很久),终点到起始点连条边,但这条边不加到网络里(因为它是虚拟固定的,不需要调整),网络流跑出来的就是最小的费用把原图调整为欧拉路的方法。
Geners | 296MS | 292K | 3845B | C++ | 2011-10-18 19:02:30 |
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=123; const int maxm=100000; const int inf=0x5fffffff; struct Edge { int v,w,c,next; }edge[maxm]; int cnt, head[maxn]; void addedge(int u, int v, int w, int c) { edge[cnt].v=v; edge[cnt].w=w; edge[cnt].c=c; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].w=0; edge[cnt].c=-c; edge[cnt].next=head[v]; head[v]=cnt++; } int dis[maxn],pre[maxn];//最小费用和前驱结点 int alpha[maxn];//标记 int que[maxn],qhead,qrear; int maxf; int spfa (int s,int e)//源汇点 { //寻找费用增广,没有返回-1; for (int i=0 ; i<maxn ; ++i) dis[i]=inf; memset (alpha , 0 , sizeof(alpha)); dis[s]=0; que[qhead=0]=s; qrear=1; alpha[s]=1; while (qhead!=qrear)//头可能大于尾 { //puts("!!"); //printf("%d %d\n",qhead, qrear); //system("pause"); int k=que[qhead++]; qhead%=maxn;//循环队列 alpha[k]=0; for (int q=head[k] ; ~q ; q=edge[q].next) if(edge[q].w) if(dis[k]+edge[q].c<dis[edge[q].v]) { dis[edge[q].v]=dis[k]+edge[q].c; //printf("%d\n", edge[q].c); pre[edge[q].v]=q; if(!alpha[edge[q].v]) { alpha[edge[q].v]=true; if(edge[q].c<0) { qhead=(qhead-1+maxn)%maxn; que[qhead]=edge[q].v; } else { que[qrear++]=edge[q].v; qrear%=maxn; } } } } if(dis[e]==inf)return -1; //终点不可达,返回-1; int k=inf; for(int i=e ; i!=s ; i=edge[pre[i]^1].v) k=min(k,edge[pre[i]].w); maxf+=k;//sum记录最大流(有些题里会用到) return k;//返回该可行流流量 } int mcmf(int s,int t) { int ans=0,k; while (~(k=spfa(s,t))) { for (int i=t ; i!=s ; i=edge[pre[i]^1].v) { edge[pre[i]].w-=k; edge[pre[i]^1].w+=k; }//更新流 ans+=dis[t]*k;//最小费用*流量 } return ans; } void init() { memset (head, -1, sizeof(head)); cnt=0; } int deg[maxn]; int n, m, s, t; int u, v, a, b; int sum, ans; int main () { int cas; //freopen ("out.txt", "r", stdin); scanf("%d",&cas); for (int I=1 ; I<=cas ; ++I) { memset (deg, 0, sizeof(deg)); init(); maxf=sum=ans=0; scanf("%d%d%d%d", &n, &m, &s, &t); ++deg[s]; --deg[t]; for(int i=0 ; i<m ; ++i) { scanf("%d%d%d%d", &u, &v, &a, &b); if(a>b) { //++deg[u]; --deg[v]; ans+=b; addedge(u, v, 1, a-b); } else { ++deg[v]; --deg[u]; ans+=a; addedge(v, u, 1, b-a); } //printf("%d %d %d\n", u, v, 1); } //++deg[s]; --deg[t]; for (int i=1 ; i<=n ; ++i) { if(deg[i]>0)addedge(0, i, deg[i], 0),sum+=deg[i]; //printf("%d %d %d\n", 0, i, deg[i]); if(deg[i]<0)addedge(i, n+1, -deg[i], 0); //printf("%d %d %d\n", i, n+1, -deg[i]); } //printf("total=%d ", ans); ans+=mcmf(0, n+1); for (int i=1 ; i<=n ; ++i) printf("%d ",deg[i]); printf("\n"); printf("%d %d\n", n, m); //printf("%d %d %d\n", ans, maxf, sum); if(maxf==sum)printf("Case %d: %d\n", I, ans); else printf("Case %d: impossible\n",I); } return 0; }