[SGU185] 网络流、求无重复边的最短路**

【题目大意】给定一个无向图,让你求两条从1到N的最短路,使得它们没用重复的边。

【算法分析】先dijkstra,然后如果d[i]+a[i][j]==d[j]的话连边[i,j](流量为1),然后求最大流,如果流量<2的话,就是无解,否则从源点dfs到汇点两次(顺着有流量的边,经过的就标记),输出路径即可。 【其它】这题空间卡得很紧。。。搞了几次才过。 【CODE】
#include #include #include #define N 401
#define E 160001
struct gtp{int x,y,op,next,c;}g[E];
int n,m,e,a[N][N];
int ls[N],cur[N],fa[N],num[N],d[N],v[N];
int flow;

void init(){
memset(a,60,sizeof(a));
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
if (wa[x][y]=w;
a[y][x]=w;
}   
}
m*=2;   
}   

void dijkstra(){
memset(v,0,sizeof(v));
for (int i=2;i<=n;i++) d[i]=a[1][i];
d[1]=0; v[1]=1;
for (;;){
int mm=a[0][0],j;
for (int i=1;i<=n;i++)
if (v[i]==0 && d[i]mm=d[i];
j=i;
}
if (mm==a[0][0]) break;
v[j]=1;
for (int i=1;i<=n;i++)
if (d[j]+a[j][i]}   
}   

inline void addedge(int x,int y,int c){
e++;
g[e].x=x; g[e].y=y; g[e].c=c; g[e].op=e+1; g[e].next=ls[x]; ls[x]=e;
e++;
g[e].x=y; g[e].y=x; g[e].c=0; g[e].op=e-1; g[e].next=ls[y]; ls[y]=e;
}   

void build(){
e=0;
memset(ls,0,sizeof(ls));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j && d[i]+a[i][j]==d[j]) addedge(i,j,1);
}   

void relabel(int k){
int mm=n;
cur[k]=ls[k];
for (int t=ls[k];t!=0;t=g[t].next)
if (g[t].c>0 && d[g[t].y]d[k]=mm+1;
}   

void change(){
flow++;
for (int i=n;i!=1;i=g[fa[i]].x){
g[fa[i]].c–;
g[g[fa[i]].op].c++;
}   
}   

void sap(){
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
for (int i=1;i<=n;i++) cur[i]=ls[i];
int i=1; num[0]=n;
while (d[1]for (;cur[i]!=0;cur[i]=g[cur[i]].next)
if (g[cur[i]].c>0 && d[g[cur[i]].y]+1==d[i]) break;
if (cur[i]==0){
if (–num[d[i]]==0) break;
relabel(i);
num[d[i]]++;
if (i!=1) i=g[fa[i]].x;
}
else{
fa[g[cur[i]].y]=cur[i];
i=g[cur[i]].y;
if (i==n){
change();
i=1;
}   
}   
}   
}   

bool dfs(int k){
if (k==n){
printf("%dn",n);
return true;
}
printf("%d ",k);
for (int t=ls[k];t!=0;t=g[t].next)
if ((t&1) && g[t].c==0){
g[t].c=-1;
if (dfs(g[t].y)) return true;
}
return false;
}   

int main(){
init();
dijkstra();
build();
sap();
if (flow<2) printf("No solutionn");
else{
dfs(1);
dfs(1);
}
return 0;
}   

[POJ 3189]枚举、网络流判定

【题目大意】给定N只牛,B个牛棚,还有每只牛给这个牛棚的打分,并且每只牛棚只能装suffer[i]只牛,让你求一个最小的分数区间[A,B],使得每只牛都能放进牛棚。

【算法分析】枚举答案,然后枚举其实分数,然后用网络流判定就行了。

还有一种做法是根据单调性,用双指针维护,相当于维护一个队列。这样会快一点,但是我写了一次,莫名其妙的TLE和WA,于是只能用这种方法。

【其它】

6376444 edward2 3189 Accepted 1320K 188MS G++ 2456B

2010-01-27 11:05:43

还算比较快

【CODE】

#include

[POJ 2594]可以用重复点的最小路径覆盖

【题目大意】给定一个无环有向图,然后求可以用重复点的最小路径覆盖。

【算法分析】既然可以用重复的,那么就可以用floyed求传递闭包,然后重复的相当于走过那条路了。然后求最小路径覆盖即可。

【HINT】记得最后要n-ans

【CODE】

#include

[POJ 1904]强连通分量、二分图匹配、巧妙转化**

【题目大意】有N个女生,N个男生,给定一些边表示这两个人可以结婚。再给定一个初始匹配,表示这个男生和哪个女生结婚。初始匹配必定是合法的。然后让你求每个男生可以和哪几个女生结婚,使得所有人都能得到婚配。

【算法分析】如果男生A可以和女生B结婚,那么连边[A,B],如果初始匹配[A,B],那么连边[B,A],最后,如果在同一个强连通分量以内,则表示可以结婚。

其实就是二分图匹配中的寻找增广路的过程,可以自己体会。

【CODE】

#include

[POJ 3660] 传递闭包

【题目大意】给定N只牛和M场比赛结果,问有多少牛的排名结果可以确定。(假设每只牛都有一个不同的力量值,大得肯定打赢小的)

【算法分析】如果A赢了B,那么连边[A,B],然后传递闭包。最后,如果某只牛的出度+入度=n-1的话,它的排名就已经确定了。

【其它】1A。这可能是除了A+Bproblem以外最短的程序了。。。水过留痕

【CODE】

#include