http://acm.ustc.edu.cn/ustcoj/problem.php?id=1280
这题是中国科大“百分点科技杯"ACM除夕挑战赛 的题目,当时做不出,后来想了一下,TLE1次,wa一次就过了
这题去掉最小费用和的边使得最短路变长,方法是先求一次最短路,然后建新图,图中存在的边当且仅当(u,v) dis[u]+w(u,v)=dis[v],题目就变成求切掉最小的边,切完后最短路必然变大,然后最小割=最大流就可做了,具体实现上就要使得if(dis[u] + e[i].w != dis[v]) e[i].c = 0;把容量变为0就等于切断了边,最短路套spfa模板,网络流套sap模板
Code:
#define inf 1<<30
#define N 1004
#define sta que
const int INF = (1<<30);
struct edge{
int u,v,w,c;
int next;//同一起点的下一条边存储在edge数组中的位置(理解了这个静态邻接表就可以了)
}e[N*25];
int head[N];//以该点为起点的第一条边存储在e数组中的位置
int dis[N];//记录与源点距离
bool vis[N];//记录顶点是否在队列中,SPFA算法可以入队列多次
int cnt[N];//记录顶点入队列次数
int ecnt;
int n,m;
void init(){
ecnt = 0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w,int cost){
e[ecnt].u = u;
e[ecnt].v = v;
e[ecnt].w = w;
e[ecnt].c = cost;
e[ecnt].next = head[u];
head[u] = ecnt++;//位置更新
/
e[ecnt].u = v;
e[ecnt].v = u;
e[ecnt].w = w;
e[ecnt].c = cost;
e[ecnt].next = head[v];
head[v] = ecnt++;
}
bool SPFA(int s){//s是源点编号
queue<int> qq;
int i;
for(i=1;i<=n;++i){
dis[i] = INF; //将除源点以外的其余点的距离设置为无穷大
vis[i] = 0;
cnt[i] = 0;
}
dis[s]=0; //源点的距离为0
vis[s] = 1;
cnt[s]++; //源点的入队列次数增加
qq.push(s);
int u,v;
while(!qq.empty()){
u = qq.front();
qq.pop();
vis[u] = 0;
for(i=head[u];i!=-1;i = e[i].next){
v = e[i].v;
int cost = e[i].w;
if(dis[v] > cost+dis[u]){
dis[v] = cost+dis[u];
if(!vis[v]){
vis[v] = 1;
qq.push(v);
cnt[v]++;
if(cnt[v] >= n)return false;
}
}
}
}
return true;
}
int h[N];
int gap[N];
int source,sink;
inline int dfs(int pos,int cost){
if (pos==sink){
return cost;
}
int j,minh=n-1,lv=cost,d;
for (j=head[pos];j!=-1;j=e[j].next){
int v=e[j].v,val=e[j].c;
if(val>0){
if (h[v]+1==h[pos]){
if (lv<e[j].c) d=lv;
else d=e[j].c;
d=dfs(v,d);
e[j].c-=d;
e[j^1].c+=d;
lv-=d;
if (h[source]>=n) return cost-lv;
if (lv==0) break;
}
if (h[v]<minh) minh=h[v];
}
}
if (lv==cost){
--gap[h[pos]];
if (gap[h[pos]]==0) h[source]=n;
h[pos]=minh+1;
++gap[h[pos]];
}
return cost-lv;
}
int sap(int st,int ed){
source=st;
sink=ed;
int ans=0;
memset(gap,0,sizeof(gap));
memset(h,0,sizeof(h));
gap[st]=n;
while (h[st]<n){
ans+=dfs(st,INT_MAX);
}
return ans;
}
int main(){
int s,t;
int ca=1;
while(scanf("%d%d",&n,&m) && (n+m)){
int i,j;
scanf("%d%d",&s,&t);
init();
for(i=0;i<m;i++){
int u,v,w,c;
scanf("%d%d%d%d",&u,&v,&w,&c);
add(u,v,w,c);
}
SPFA(s);//cout<<ecnt<<endl;
for(i=0;i<ecnt;i+=2){
int u = e[i].u;
int v = e[i].v;
//if(u==1 && v==4){e[i].c=0;e[i+1].c=1;continue;}
if(dis[u] + e[i].w != dis[v]){
e[i].c = 0;
}
if(dis[v] + e[i].w != dis[u]){
e[i+1].c=0;
}
}
//for(i=0;i<ecnt;i++)cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].c<<endl;
printf("Case %d: %d\n",ca++,sap(s,t));
}
return 0;
}