题意:花最小的费用进行删边操作使图变为欧拉路
题解:模仿混合图欧拉路的构图方法,不过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;
}