本文系转载,原创请访问:http://blog.youkuaiyun.com/zhou_yujia/article/details/51427382
1、模板题 我是用prim搞得 给出每点坐标求最小生成树
hdu1162Eddy's picture 最小生成树
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- using namespace std;
- int flag1=0;
- double sum;
- double arr_list[110][110];
- struct Edge
- {
- int point;
- double lowcost;
- int flag;
- };
- Edge edge[12100];
- struct Point
- {
- double x,y;
- }point[110];
- double prim(int n)
- {
- int i,j,k=1,flag;
- double min,sum2=0;
- j=1;
- for(i=1;i<=n;i++)
- {
- if(i!=j)
- {
- edge[i].point=i;
- edge[i].lowcost=arr_list[j][i];
- edge[i].flag=0;
- }
- }
- edge[j].lowcost=0;
- edge[j].flag=1;
- for(i=2;i<=n;i++)
- {
- k=1;
- min=65535;
- flag=0;
- for(j=2;j<=n;j++)
- {
- if(edge[j].flag==0&&edge[j].lowcost<min)
- {
- k=j;
- min=edge[j].lowcost;
- flag=1;
- }
- }
- if(!flag) return -1;
- sum2+=min;
- edge[k].flag=1;
- for(j=2;j<=n;j++)
- {
- if(edge[j].flag==0&&arr_list[k][j]<edge[j].lowcost)
- {
- edge[j].point=k;
- edge[j].lowcost=arr_list[k][j];
- }
- }
- }
- return sum2;
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- int n;
- while(~scanf("%d",&n))
- {
- for(int i=1;i<=n;i++)
- {
- cin>>point[i].x>>point[i].y;
- arr_list[i][i]=65535;
- }
- for(int i=1;i<n;i++)
- {
- for(int j=i+1;j<=n;j++)
- {
- arr_list[i][j]=sqrt(pow((point[i].x-point[j].x),2)+pow((point[i].y-point[j].y),2));
- arr_list[j][i]=arr_list[i][j];
- //cout<<arr_list[i][j]<<endl;
- }
- }
- sum=prim(n);
- printf("%.2lf\n",sum);
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int flag1=0;
double sum;
double arr_list[110][110];
struct Edge
{
int point;
double lowcost;
int flag;
};
Edge edge[12100];
struct Point
{
double x,y;
}point[110];
double prim(int n)
{
int i,j,k=1,flag;
double min,sum2=0;
j=1;
for(i=1;i<=n;i++)
{
if(i!=j)
{
edge[i].point=i;
edge[i].lowcost=arr_list[j][i];
edge[i].flag=0;
}
}
edge[j].lowcost=0;
edge[j].flag=1;
for(i=2;i<=n;i++)
{
k=1;
min=65535;
flag=0;
for(j=2;j<=n;j++)
{
if(edge[j].flag==0&&edge[j].lowcost<min)
{
k=j;
min=edge[j].lowcost;
flag=1;
}
}
if(!flag) return -1;
sum2+=min;
edge[k].flag=1;
for(j=2;j<=n;j++)
{
if(edge[j].flag==0&&arr_list[k][j]<edge[j].lowcost)
{
edge[j].point=k;
edge[j].lowcost=arr_list[k][j];
}
}
}
return sum2;
}
int main()
{
// freopen("cin.txt","r",stdin);
int n;
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
cin>>point[i].x>>point[i].y;
arr_list[i][i]=65535;
}
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
arr_list[i][j]=sqrt(pow((point[i].x-point[j].x),2)+pow((point[i].y-point[j].y),2));
arr_list[j][i]=arr_list[i][j];
//cout<<arr_list[i][j]<<endl;
}
}
sum=prim(n);
printf("%.2lf\n",sum);
}
return 0;
}
2、模板题 floyd最短路相加改成相乘
- #include <iostream>
- #include<cstdio>
- using namespace std;
- double dist[1005][1005];
- int main()
- {
- // freopen("cin.txt","r",stdin);
- int n,q,a,b;
- while(~scanf("%d",&n))
- {
- for(int i=0;i<n;i++)
- {
- for(int j=0;j<n;j++)
- {
- scanf("%lf",&dist[i][j]);
- }
- }
- for(int i=0;i<n;i++)
- {
- for(int j=0;j<n;j++)
- {
- for(int k=0;k<n;k++)
- {
- if(dist[j][i]*dist[i][k]>dist[j][k])
- dist[j][k]=dist[j][i]*dist[i][k];
- }
- }
- }
- scanf("%d",&q);
- while(q--)
- {
- scanf("%d%d",&a,&b);
- a--;b--;
- if(dist[a][b]>0.000001)
- printf("%.3lf\n",dist[a][b]);
- else puts("What a pity!");
- }
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
using namespace std;
double dist[1005][1005];
int main()
{
// freopen("cin.txt","r",stdin);
int n,q,a,b;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%lf",&dist[i][j]);
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
if(dist[j][i]*dist[i][k]>dist[j][k])
dist[j][k]=dist[j][i]*dist[i][k];
}
}
}
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&a,&b);
a--;b--;
if(dist[a][b]>0.000001)
printf("%.3lf\n",dist[a][b]);
else puts("What a pity!");
}
}
return 0;
}
3、稍微转弯的prim 题意:p个哨所间只有s个卫星通道,但每个哨所都有无线发射器,无线发射的功率随长度增加而增加但是每个都一样,问最小长度?
我们知道prim算法中的步骤是每次加入最小的边,但是并没有将加入的边存储下来,加一个数组存储下来,倒序排序,前s个边用卫星通道就好啦
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- #include<algorithm>
- using namespace std;
- int flag1=0;
- int n,s,p;
- double sum;
- double arr_list[504][504];
- double d[503];
- struct Edge
- {
- int point;
- double lowcost;
- int flag;
- };
- Edge edge[505];
- bool cmp(double a,double b)
- {
- return a>b;
- }
- struct Point
- {
- double x,y;
- }point[502];
- void prim(int p)
- {
- int i,j,k=1;
- double min,sum2=0;
- j=1;
- for(i=1;i<=p;i++)
- {
- if(i!=j)
- {
- edge[i].point=j;
- edge[i].lowcost=arr_list[j][i];
- edge[i].flag=0;
- }
- }
- edge[j].lowcost=0;
- edge[j].flag=1;
- int l=0;
- for(i=1;i<p;i++)
- {
- min=65535000;
- for(j=2;j<=p;j++)
- {
- if(edge[j].flag==0&&edge[j].lowcost<min)
- {
- k=j;
- min=edge[j].lowcost;
- }
- }
- d[l++]=arr_list[k][edge[k].point];
- //sum2+=min;
- edge[k].flag=1;
- for(j=2;j<=p;j++)
- {
- if(edge[j].flag==0&&arr_list[k][j]<edge[j].lowcost)
- {
- edge[j].point=k;
- edge[j].lowcost=arr_list[k][j];
- }
- }
- }
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- cin>>n;
- while(n--)
- {
- cin>>s>>p;
- for(int i=1;i<=p;i++)
- {
- cin>>point[i].x>>point[i].y;
- arr_list[i][i]=65535000;
- }
- for(int i=1;i<p;i++)
- {
- for(int j=i+1;j<=p;j++)
- {
- arr_list[i][j]=sqrt(pow((point[i].x-point[j].x),2)+pow((point[i].y-point[j].y),2));
- arr_list[j][i]=arr_list[i][j];
- //cout<<arr_list[i][j]<<endl;
- }
- }
- prim(p);
- sort(d,d+p-1,cmp);
- cout.setf(ios::fixed);//保留两位小数
- cout.precision(2);
- cout<<d[s-1]<<endl;
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int flag1=0;
int n,s,p;
double sum;
double arr_list[504][504];
double d[503];
struct Edge
{
int point;
double lowcost;
int flag;
};
Edge edge[505];
bool cmp(double a,double b)
{
return a>b;
}
struct Point
{
double x,y;
}point[502];
void prim(int p)
{
int i,j,k=1;
double min,sum2=0;
j=1;
for(i=1;i<=p;i++)
{
if(i!=j)
{
edge[i].point=j;
edge[i].lowcost=arr_list[j][i];
edge[i].flag=0;
}
}
edge[j].lowcost=0;
edge[j].flag=1;
int l=0;
for(i=1;i<p;i++)
{
min=65535000;
for(j=2;j<=p;j++)
{
if(edge[j].flag==0&&edge[j].lowcost<min)
{
k=j;
min=edge[j].lowcost;
}
}
d[l++]=arr_list[k][edge[k].point];
//sum2+=min;
edge[k].flag=1;
for(j=2;j<=p;j++)
{
if(edge[j].flag==0&&arr_list[k][j]<edge[j].lowcost)
{
edge[j].point=k;
edge[j].lowcost=arr_list[k][j];
}
}
}
}
int main()
{
// freopen("cin.txt","r",stdin);
cin>>n;
while(n--)
{
cin>>s>>p;
for(int i=1;i<=p;i++)
{
cin>>point[i].x>>point[i].y;
arr_list[i][i]=65535000;
}
for(int i=1;i<p;i++)
{
for(int j=i+1;j<=p;j++)
{
arr_list[i][j]=sqrt(pow((point[i].x-point[j].x),2)+pow((point[i].y-point[j].y),2));
arr_list[j][i]=arr_list[i][j];
//cout<<arr_list[i][j]<<endl;
}
}
prim(p);
sort(d,d+p-1,cmp);
cout.setf(ios::fixed);//保留两位小数
cout.precision(2);
cout<<d[s-1]<<endl;
}
return 0;
}
4、多源点单汇点 之前都是单源最短路,如果是多源单汇点的话也是一样的
hdu2680Choose the best route dijkstra
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #define MaxN 10010
- #define MaxInt 2000000
- using namespace std;
- int map[MaxN][MaxN],dist[MaxN],start;
- bool mark[MaxN];
- int n,m,s,p,q,t,w,b,end,min1,minn,ww;
- void dijkstra(int s)
- {
- memset(mark,0,sizeof(mark));
- for(int i=1;i<=n;i++) dist[i]=map[s][i];
- mark[s]=1;dist[s]=0;
- int k;
- for(int i=1;i<n;i++)
- {
- minn=MaxInt;
- for(int j=1;j<=n;j++)
- {
- if(!mark[j]&&minn>dist[j])
- {
- k=j;
- minn=dist[j];
- }
- }
- if(minn==MaxInt) break;
- mark[k]=1;
- for(int j=1;j<=n;j++)
- {
- if(!mark[j]&&dist[j]>dist[k]+map[k][j])
- {
- dist[j]=dist[k]+map[k][j];
- }
- }
- }
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- while(~scanf("%d%d%d",&n,&m,&s))
- {
- for(int i=1;i<=n;i++)
- {
- for(int j=1;j<=n;j++)
- {
- map[i][j]=MaxInt;
- }
- }
- for(int i=0;i<m;i++)
- {
- scanf("%d%d%d",&p,&q,&t);
- if(t<map[q][p])
- map[q][p]=t;
- }
- dijkstra(s);
- min1=MaxInt;
- scanf("%d",&w);
- while(w--)
- {
- scanf("%d",&ww);
- if(min1>dist[ww]) min1=dist[ww];
- }
- if(min1!=MaxInt)
- printf("%d\n",min1);
- else printf("-1\n");
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#define MaxN 10010
#define MaxInt 2000000
using namespace std;
int map[MaxN][MaxN],dist[MaxN],start;
bool mark[MaxN];
int n,m,s,p,q,t,w,b,end,min1,minn,ww;
void dijkstra(int s)
{
memset(mark,0,sizeof(mark));
for(int i=1;i<=n;i++) dist[i]=map[s][i];
mark[s]=1;dist[s]=0;
int k;
for(int i=1;i<n;i++)
{
minn=MaxInt;
for(int j=1;j<=n;j++)
{
if(!mark[j]&&minn>dist[j])
{
k=j;
minn=dist[j];
}
}
if(minn==MaxInt) break;
mark[k]=1;
for(int j=1;j<=n;j++)
{
if(!mark[j]&&dist[j]>dist[k]+map[k][j])
{
dist[j]=dist[k]+map[k][j];
}
}
}
}
int main()
{
// freopen("cin.txt","r",stdin);
while(~scanf("%d%d%d",&n,&m,&s))
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
map[i][j]=MaxInt;
}
}
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&p,&q,&t);
if(t<map[q][p])
map[q][p]=t;
}
dijkstra(s);
min1=MaxInt;
scanf("%d",&w);
while(w--)
{
scanf("%d",&ww);
if(min1>dist[ww]) min1=dist[ww];
}
if(min1!=MaxInt)
printf("%d\n",min1);
else printf("-1\n");
}
return 0;
}
5、限定必须连上给定的两点 这是一个关于最小生成树的原理应用,也是以签到题的姿态出现的区域赛题
HDU 4463 Outlets 最小生成树Kr~
既然要求他俩必须先连,那就先连上,逐渐选择最小的边加入边集中就ok啦- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #include<cmath>
- #include<algorithm>
- using namespace std;
- const int maxn=60*60;
- struct point
- {
- int x,y;
- double dis;
- point(){}
- point(int _x,int _y,double _d):x(_x),y(_y),dis(_d){}
- bool operator <(const struct point &tmp)const{
- return this->dis<tmp.dis;
- }
- }p[maxn];
- point pp[100];
- int par[60];
- void init(){
- for(int i=0;i<60;i++) par[i]=i;
- }
- int find_par(int x){
- if(x!=par[x]) return par[x]=find_par(par[x]);
- return par[x];
- }
- bool Union(int x,int y){
- x=find_par(x);
- y=find_par(y);
- if(x!=y){
- par[y]=x;
- return true;
- }
- return false;
- }
- double calu(point a,point b){
- return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- int n,p1,q1;
- while(~scanf("%d",&n)&&n)
- {
- init();
- scanf("%d%d",&p1,&q1);
- int cnt=0;
- for(int i=1;i<=n;i++)
- {
- int x,y;
- scanf("%d%d",&pp[i].x,&pp[i].y);
- for(int j=1;j<i;j++)
- {
- double d=calu(pp[i],pp[j]);
- p[cnt++]=point(i,j,d);
- }
- }
- double ans=0;
- Union(p1,q1);
- ans+=calu(pp[p1],pp[q1]);
- sort(p,p+cnt);
- for(int i=0;i<cnt;i++)
- {
- if(Union(p[i].x,p[i].y))
- ans+=p[i].dis;
- }
- printf("%.2lf\n",ans);
- }
- }
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=60*60;
struct point
{
int x,y;
double dis;
point(){}
point(int _x,int _y,double _d):x(_x),y(_y),dis(_d){}
bool operator <(const struct point &tmp)const{
return this->dis<tmp.dis;
}
}p[maxn];
point pp[100];
int par[60];
void init(){
for(int i=0;i<60;i++) par[i]=i;
}
int find_par(int x){
if(x!=par[x]) return par[x]=find_par(par[x]);
return par[x];
}
bool Union(int x,int y){
x=find_par(x);
y=find_par(y);
if(x!=y){
par[y]=x;
return true;
}
return false;
}
double calu(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
// freopen("cin.txt","r",stdin);
int n,p1,q1;
while(~scanf("%d",&n)&&n)
{
init();
scanf("%d%d",&p1,&q1);
int cnt=0;
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&pp[i].x,&pp[i].y);
for(int j=1;j<i;j++)
{
double d=calu(pp[i],pp[j]);
p[cnt++]=point(i,j,d);
}
}
double ans=0;
Union(p1,q1);
ans+=calu(pp[p1],pp[q1]);
sort(p,p+cnt);
for(int i=0;i<cnt;i++)
{
if(Union(p[i].x,p[i].y))
ans+=p[i].dis;
}
printf("%.2lf\n",ans);
}
}
6、floyd最小环 裸题 前一个是输出路径
poj1734Sightseeing trip floyd最小环
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<queue>
- #include<cstdio>
- #include<climits>
- #include<algorithm>
- using namespace std;
- const int N=111;
- const int INF=0xffffff;
- int min_loop;
- int num;
- int map[N][N],dist[N][N],pre[N][N];
- int path[N];
- int n,m;
- void dfs(int i,int j)
- {
- int k=pre[i][j];
- if(k==0)
- {
- path[num++]=j;
- return;
- }
- dfs(i,k);
- dfs(k,j);
- }
- void Floyd()
- {
- min_loop=INF;
- memset(pre,0,sizeof(pre));
- for(int k=1; k<=n; k++)
- {
- for(int i=1; i<k; i++)
- {
- for(int j=i+1; j<k; j++)
- {
- if(dist[i][j]+map[i][k]+map[k][j]<min_loop)
- {
- min_loop=dist[i][j]+map[i][k]+map[k][j];
- num=0;
- path[num++]=i;
- dfs(i,j);
- path[num++]=k;
- }
- }
- }
- for(int i=1; i<=n; i++)
- {
- for(int j=1; j<=n; j++)
- {
- if(dist[i][k]+dist[k][j]<dist[i][j])
- {
- dist[i][j]=dist[i][k]+dist[k][j];
- pre[i][j]=k;
- }
- }
- }
- }
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- while(~scanf("%d%d",&n,&m))
- {
- for(int i=1; i<=n; i++)
- {
- for(int j=i+1; j<=n; j++)
- map[i][j]=map[j][i]=dist[i][j]=dist[j][i]=INF;
- map[i][i]=dist[i][i]=0;
- }
- for(int i=0; i<m; i++)
- {
- int u,v,w;
- scanf("%d%d%d",&u,&v,&w);
- if(w<map[u][v])
- {
- map[u][v]=map[v][u]=w;
- dist[u][v]=dist[v][u]=w;
- }
- }
- Floyd();
- if(min_loop==INF)
- puts("No solution.");
- else
- {
- for(int i=0; i<num-1; i++) printf("%d ",path[i]);
- printf("%d\n",path[num-1]);
- //printf("%d\n",min_loop);
- }
- }
- return 0;
- }
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cstdio>
#include<climits>
#include<algorithm>
using namespace std;
const int N=111;
const int INF=0xffffff;
int min_loop;
int num;
int map[N][N],dist[N][N],pre[N][N];
int path[N];
int n,m;
void dfs(int i,int j)
{
int k=pre[i][j];
if(k==0)
{
path[num++]=j;
return;
}
dfs(i,k);
dfs(k,j);
}
void Floyd()
{
min_loop=INF;
memset(pre,0,sizeof(pre));
for(int k=1; k<=n; k++)
{
for(int i=1; i<k; i++)
{
for(int j=i+1; j<k; j++)
{
if(dist[i][j]+map[i][k]+map[k][j]<min_loop)
{
min_loop=dist[i][j]+map[i][k]+map[k][j];
num=0;
path[num++]=i;
dfs(i,j);
path[num++]=k;
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(dist[i][k]+dist[k][j]<dist[i][j])
{
dist[i][j]=dist[i][k]+dist[k][j];
pre[i][j]=k;
}
}
}
}
}
int main()
{
// freopen("cin.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
for(int i=1; i<=n; i++)
{
for(int j=i+1; j<=n; j++)
map[i][j]=map[j][i]=dist[i][j]=dist[j][i]=INF;
map[i][i]=dist[i][i]=0;
}
for(int i=0; i<m; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(w<map[u][v])
{
map[u][v]=map[v][u]=w;
dist[u][v]=dist[v][u]=w;
}
}
Floyd();
if(min_loop==INF)
puts("No solution.");
else
{
for(int i=0; i<num-1; i++) printf("%d ",path[i]);
printf("%d\n",path[num-1]);
//printf("%d\n",min_loop);
}
}
return 0;
}
7、单向最短路来回最短距离 虽说是来回都得求值,还记不记得之前的“孙大神的山峰序列” 一样的道理,从两边求完之后遍历数组求和最小即为答案
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<queue>
- #include<cstdio>
- using namespace std;
- int n,m,x;
- const int MAXINT=0x3f3f3f3f;
- const int MAXNUM=1100;
- int dist[MAXNUM];
- int A[MAXNUM][MAXNUM];
- void Dijkstra(int v0)
- {
- bool S[MAXNUM];// 判断是否已存入该点到S集合中
- for(int i=1; i<=n; ++i)
- {
- dist[i]=A[v0][i];
- // printf("%d ",dist[i]);
- S[i]=false; // 初始都未用过该点
- }
- // dist[v0] = 0;
- S[v0]=true;
- for(int i=2; i<=n; i++)
- {
- int mindist = MAXINT;
- int u = -1;// 找出当前未使用的点j的dist[j]最小值
- for(int j=1; j<=n; ++j)
- if((!S[j]) && dist[j]<mindist)
- {
- u = j;// u保存当前邻接点中距离最小的点的号码
- mindist = dist[j];
- //printf("%d ",mindist);
- }
- S[u] = true;
- for(int j=1; j<=n; j++)
- if((!S[j]) && A[u][j]<MAXINT)
- {
- if(dist[u] + A[u][j] < dist[j]) //在通过新加入的u点路径找到离v0点更短的路径
- {
- dist[j] = dist[u] + A[u][j]; //更新dis //记录前驱顶点
- }
- }
- }
- return;
- }
- int main()
- {
- //freopen("cin.txt","r",stdin);
- while(~scanf("%d%d%d",&n,&m,&x))
- {
- for(int i=1; i<=n; i++)
- {
- for(int j=i+1; j<=n; j++)
- A[i][j]=A[j][i]=MAXINT;
- }
- for(int i=0; i<m; i++)
- {
- int u,v,w;
- scanf("%d%d%d",&u,&v,&w);
- A[u][v]=w;
- //printf("%d %d %d\n",u,v,A[u][v]);
- }
- Dijkstra(x);
- int a1[MAXNUM],a2[MAXNUM];
- for(int i=1;i<=n;i++) a1[i]=dist[i];//printf("%d ",a1[i]);
- // puts("");
- for(int i=1;i<=n;i++)
- for(int j=i+1;j<=n;j++)
- {
- int tmp;
- tmp=A[i][j];
- A[i][j]=A[j][i];
- A[j][i]=tmp;
- }
- Dijkstra(x);
- for(int i=1;i<=n;i++) a2[i]=dist[i];
- int minn=0;
- for(int i=1;i<=n;i++)
- {
- minn=max(minn,a1[i]+a2[i]);
- }
- printf("%d\n",minn);
- }
- return 0;
- }
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cstdio>
using namespace std;
int n,m,x;
const int MAXINT=0x3f3f3f3f;
const int MAXNUM=1100;
int dist[MAXNUM];
int A[MAXNUM][MAXNUM];
void Dijkstra(int v0)
{
bool S[MAXNUM];// 判断是否已存入该点到S集合中
for(int i=1; i<=n; ++i)
{
dist[i]=A[v0][i];
// printf("%d ",dist[i]);
S[i]=false; // 初始都未用过该点
}
// dist[v0] = 0;
S[v0]=true;
for(int i=2; i<=n; i++)
{
int mindist = MAXINT;
int u = -1;// 找出当前未使用的点j的dist[j]最小值
for(int j=1; j<=n; ++j)
if((!S[j]) && dist[j]<mindist)
{
u = j;// u保存当前邻接点中距离最小的点的号码
mindist = dist[j];
//printf("%d ",mindist);
}
S[u] = true;
for(int j=1; j<=n; j++)
if((!S[j]) && A[u][j]<MAXINT)
{
if(dist[u] + A[u][j] < dist[j]) //在通过新加入的u点路径找到离v0点更短的路径
{
dist[j] = dist[u] + A[u][j]; //更新dis //记录前驱顶点
}
}
}
return;
}
int main()
{
//freopen("cin.txt","r",stdin);
while(~scanf("%d%d%d",&n,&m,&x))
{
for(int i=1; i<=n; i++)
{
for(int j=i+1; j<=n; j++)
A[i][j]=A[j][i]=MAXINT;
}
for(int i=0; i<m; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
A[u][v]=w;
//printf("%d %d %d\n",u,v,A[u][v]);
}
Dijkstra(x);
int a1[MAXNUM],a2[MAXNUM];
for(int i=1;i<=n;i++) a1[i]=dist[i];//printf("%d ",a1[i]);
// puts("");
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int tmp;
tmp=A[i][j];
A[i][j]=A[j][i];
A[j][i]=tmp;
}
Dijkstra(x);
for(int i=1;i<=n;i++) a2[i]=dist[i];
int minn=0;
for(int i=1;i<=n;i++)
{
minn=max(minn,a1[i]+a2[i]);
}
printf("%d\n",minn);
}
return 0;
}
8、换货币,给出汇率,问是否可以通过一系列的折腾使得手中的钱增多,其实也不容想到是用floyd最短路的方法写== dist[i][i]>1.0即为钱数增加
POJ 2240 Arbitrage floyd
- #include <iostream>
- #include <cstdio>
- #include<map>
- #include <string.h>
- using namespace std;
- map<string,int>mat;
- double dist[100][100];
- int n,m;
- void Floyd()
- {
- for(int k=1;k<=n;k++)
- for(int i=1; i<=n; i++)
- {
- for(int j=1; j<=n; j++)
- {
- if(dist[i][k]*dist[k][j]>dist[i][j])
- {
- dist[i][j]=dist[i][k]*dist[k][j];
- // pre[i][j]=k;
- }
- }
- }
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- map<string,int>mat;
- int cnt=0;
- double w;
- string str,str1,str2;
- while(~scanf("%d",&n)&&n)
- {
- //mat.clear();
- for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
- {
- if(i==j) dist[i][j]=1;
- else dist[i][j]=0;
- }
- for(int i=1;i<=n;i++) cin>>str,mat[str]=i;
- cin>>m;
- while(m--)
- {
- cin>>str1>>w>>str2;
- dist[mat[str1]][mat[str2]]=w;
- //maap[mat[str1]][mat[str2]]=w;
- }
- Floyd();
- printf("Case %d:",++cnt);
- bool flag=false;
- for(int i=1;i<=n;i++)
- if(dist[i][i]>1.0)
- {
- flag=true;
- break;
- }
- if(!flag) printf(" No\n");
- else printf(" Yes\n");
- }
- return 0;
- }
#include <iostream>
#include <cstdio>
#include<map>
#include <string.h>
using namespace std;
map<string,int>mat;
double dist[100][100];
int n,m;
void Floyd()
{
for(int k=1;k<=n;k++)
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(dist[i][k]*dist[k][j]>dist[i][j])
{
dist[i][j]=dist[i][k]*dist[k][j];
// pre[i][j]=k;
}
}
}
}
int main()
{
// freopen("cin.txt","r",stdin);
map<string,int>mat;
int cnt=0;
double w;
string str,str1,str2;
while(~scanf("%d",&n)&&n)
{
//mat.clear();
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
{
if(i==j) dist[i][j]=1;
else dist[i][j]=0;
}
for(int i=1;i<=n;i++) cin>>str,mat[str]=i;
cin>>m;
while(m--)
{
cin>>str1>>w>>str2;
dist[mat[str1]][mat[str2]]=w;
//maap[mat[str1]][mat[str2]]=w;
}
Floyd();
printf("Case %d:",++cnt);
bool flag=false;
for(int i=1;i<=n;i++)
if(dist[i][i]>1.0)
{
flag=true;
break;
}
if(!flag) printf(" No\n");
else printf(" Yes\n");
}
return 0;
}
9、换货币,给出汇率和手续费,问是否可以使得手里钱增加 spfa
POJ 1860 Currency Exchange spfa
同样是换货币,之前的题是只有汇率,这个题还有手续费,spfa bellman都可做,我当时用的前者。为什么要用这两个方法,因为要判断"负环",当然了这个题存在“钱无限增加”的情况就说明松弛操作可以进行很多次,就是正常函数返回-1的情况==
- #include <iostream>
- #include <cstdio>
- #include <cmath>
- #include <queue>
- #include <string.h>
- using namespace std;
- const int INF=0x3f3f3f3f;
- const int maxm=511111;
- const int maxn=111111;
- struct EdgeNode
- {
- int to;
- int next;
- double rate,comm,w;
- };
- int cont[maxn];
- EdgeNode edges[maxm];
- int N,M,s;
- double val;
- int head[maxn],edge;
- bool vis[maxn];
- queue <int> que;
- double dis[maxn];
- void addedge(int u,int v,double r,double c)
- {
- edges[edge].comm=c,edges[edge].to=v;
- edges[edge].next=head[u];edges[edge].w=0;
- edges[edge].rate=r;head[u]=edge++;
- }
- void init()
- {
- memset(head,-1,sizeof(head));
- edge=0;
- memset(cont,0,sizeof(cont));
- memset(vis,false,sizeof(vis));
- for (int i=0; i<N; i++)
- dis[i]=0;
- }
- int spfa(int s,int n)//单源最短路(s为起点,n为节点总数)///
- {
- int u;
- while (!que.empty()) que.pop();
- vis[s]=true;
- dis[s]=val;
- ++cont[s];
- que.push(s);
- while (!que.empty())
- {
- u=que.front();
- que.pop();
- vis[u]=false;
- for (int i=head[u]; i!=-1; i=edges[i].next)
- {
- int v=edges[i].to;
- edges[i].w=(dis[u]-edges[i].comm)*edges[i].rate-dis[u];
- if (dis[v]<dis[u]+edges[i].w)///
- {
- dis[v]=dis[u]+edges[i].w;
- if (!vis[v])
- {
- vis[v]=true;
- que.push(v);
- }
- if(++cont[v]>n)
- return -1;
- }
- }
- }
- return 1;
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- while(~scanf("%d%d%d%lf",&N,&M,&s,&val))
- {
- int a,b;
- init();
- double rab,cab,rba,cba;
- while(M--)
- {
- scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
- addedge(a,b,rab,cab);
- addedge(b,a,rba,cba);
- }
- if(spfa(s,N)==-1)printf("YES\n");
- else printf("NO\n");
- }
- return 0;
- }
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <string.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxm=511111;
const int maxn=111111;
struct EdgeNode
{
int to;
int next;
double rate,comm,w;
};
int cont[maxn];
EdgeNode edges[maxm];
int N,M,s;
double val;
int head[maxn],edge;
bool vis[maxn];
queue <int> que;
double dis[maxn];
void addedge(int u,int v,double r,double c)
{
edges[edge].comm=c,edges[edge].to=v;
edges[edge].next=head[u];edges[edge].w=0;
edges[edge].rate=r;head[u]=edge++;
}
void init()
{
memset(head,-1,sizeof(head));
edge=0;
memset(cont,0,sizeof(cont));
memset(vis,false,sizeof(vis));
for (int i=0; i<N; i++)
dis[i]=0;
}
int spfa(int s,int n)//单源最短路(s为起点,n为节点总数)///
{
int u;
while (!que.empty()) que.pop();
vis[s]=true;
dis[s]=val;
++cont[s];
que.push(s);
while (!que.empty())
{
u=que.front();
que.pop();
vis[u]=false;
for (int i=head[u]; i!=-1; i=edges[i].next)
{
int v=edges[i].to;
edges[i].w=(dis[u]-edges[i].comm)*edges[i].rate-dis[u];
if (dis[v]<dis[u]+edges[i].w)///
{
dis[v]=dis[u]+edges[i].w;
if (!vis[v])
{
vis[v]=true;
que.push(v);
}
if(++cont[v]>n)
return -1;
}
}
}
return 1;
}
int main()
{
// freopen("cin.txt","r",stdin);
while(~scanf("%d%d%d%lf",&N,&M,&s,&val))
{
int a,b;
init();
double rab,cab,rba,cba;
while(M--)
{
scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
addedge(a,b,rab,cab);
addedge(b,a,rba,cba);
}
if(spfa(s,N)==-1)printf("YES\n");
else printf("NO\n");
}
return 0;
}
10、差分约束入门题 分糖果“小于等于” by the way 小于等于是最短路 大于等于是最长路
POJ 3159 Candies差分约束系统 spfa
核心在于:xj-xi<=bk,会发现它类似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- using namespace std;
- const int maxn=30005;
- int dis[maxn],head[maxn];
- int n,m,sum;
- bool vis[maxn];
- struct node{
- int v,w,next;
- }edge[150010];
- void addedge(int a,int b,int c){
- edge[sum].v=b;
- edge[sum].w=c;
- edge[sum].next=head[a];
- head[a]=sum++;
- }
- bool spfa(int s){
- int stack[maxn],outque[maxn],top=0;
- memset(dis,0x3f,sizeof(dis));
- memset(vis,0,sizeof(vis));
- memset(outque,0,sizeof(outque));
- stack[top++]=s;
- vis[s]=1;//vis数组的作用不是判断它是否被更新过 而是是否在栈里!
- dis[s]=0;
- while(top){
- int tmp=stack[--top];
- vis[tmp]=0;
- outque[tmp]++;
- if(outque[tmp]>n) return 0; //判断负环,当然这里没有必要写它
- int k=head[tmp];
- while(k>-1){
- if(dis[edge[k].v]>edge[k].w+dis[tmp]){
- dis[edge[k].v]=edge[k].w+dis[tmp];
- if(vis[edge[k].v]==0){
- vis[edge[k].v]=1;
- stack[top++]=edge[k].v;
- }
- }
- k=edge[k].next;
- }
- }
- return 1;
- }
- int main()
- {
- //freopen("cin.txt","r",stdin);
- while(cin>>n>>m){
- sum=0;
- memset(head,-1,sizeof(head));
- int a,b,c;
- while(m--){
- scanf("%d%d%d",&a,&b,&c);
- addedge(a,b,c);
- }
- spfa(1);
- printf("%d\n",dis[n]);
- }
- return 0;
- }
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=30005;
int dis[maxn],head[maxn];
int n,m,sum;
bool vis[maxn];
struct node{
int v,w,next;
}edge[150010];
void addedge(int a,int b,int c){
edge[sum].v=b;
edge[sum].w=c;
edge[sum].next=head[a];
head[a]=sum++;
}
bool spfa(int s){
int stack[maxn],outque[maxn],top=0;
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(outque,0,sizeof(outque));
stack[top++]=s;
vis[s]=1;//vis数组的作用不是判断它是否被更新过 而是是否在栈里!
dis[s]=0;
while(top){
int tmp=stack[--top];
vis[tmp]=0;
outque[tmp]++;
if(outque[tmp]>n) return 0; //判断负环,当然这里没有必要写它
int k=head[tmp];
while(k>-1){
if(dis[edge[k].v]>edge[k].w+dis[tmp]){
dis[edge[k].v]=edge[k].w+dis[tmp];
if(vis[edge[k].v]==0){
vis[edge[k].v]=1;
stack[top++]=edge[k].v;
}
}
k=edge[k].next;
}
}
return 1;
}
int main()
{
//freopen("cin.txt","r",stdin);
while(cin>>n>>m){
sum=0;
memset(head,-1,sizeof(head));
int a,b,c;
while(m--){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
}
spfa(1);
printf("%d\n",dis[n]);
}
return 0;
}
11、差分约束系统论文题
题意:每天每个时间有一定的收银员人数需求(以小时为单位)另有很多人应聘,一旦应聘,干满8小时,问最少雇佣多少人
s[]数组表示共雇佣了的人数,num[] 当前时刻最多可雇佣人数,r[]某时刻的最少人数。1. s[i]-s[i-1]>=0 2. s[i-1]-s[i]>=-num[i] (1<=i<=24) 3. s[i]-s[i-8]>=r[i](8<=i<=24) 4. s[i]-s[i+16]>=r[i]-ans (1<=i<=8) 5. s[24]-s[0]>=ans 注意第4个式子,是将第3个式子扩展到"每天"得到的
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<vector>
- #include<queue>
- using namespace std;
- const int inf=0x3f3f3f3f;
- const int maxn=50005;
- struct Edge
- {
- int v,cost;
- Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
- };
- vector<Edge>E[maxn];
- void addedge(int u,int v,int w)
- {
- E[u].push_back(Edge(v,w));
- }
- bool vis[maxn];
- int cnt[maxn];
- int dist[maxn];
- bool spfa(int start,int n)
- {
- memset(vis,false,sizeof(vis));
- memset(dist,-inf,sizeof(dist));
- vis[start]=true;
- dist[start]=0;
- queue<int>que;
- while(!que.empty()) que.pop();
- que.push(start);
- memset(cnt,0,sizeof(cnt));
- cnt[start]=1;
- while(!que.empty())
- {
- int u=que.front();
- que.pop();
- vis[u]=false;
- for(int i=0;i<E[u].size();i++)
- {
- int v=E[u][i].v;
- if(dist[v]<dist[u]+E[u][i].cost)
- {
- dist[v]=dist[u]+E[u][i].cost;
- if(!vis[v])
- {
- vis[v]=true;
- que.push(v);
- if(++cnt[v]>n) return false;
- }
- }
- }
- }
- return true;
- }
- int num[30],r[30];
- int main()
- {
- //freopen("cin.txt","r",stdin);
- int t,ans,m;
- scanf("%d",&t);
- while(t--)
- {
- for(int i=1;i<=24;i++) scanf("%d",&r[i]);
- for(int i=0;i<25;i++) num[i]=0;
- scanf("%d",&m);
- for(int i=0;i<m;i++)
- {
- int tmp;
- scanf("%d",&tmp);
- num[tmp+1]++;///!!!
- }
- ans=1;
- bool flag=true;
- int l=0,right=m;
- while(l<right)
- {
- for(int i=0;i<=24;i++) E[i].clear();
- ans=(l+right)/2;
- for(int i=1;i<=24;i++)
- {
- addedge(i-1,i,0);
- addedge(i,i-1,-num[i]);
- }
- for(int i=8;i<=24;i++) addedge(i-8,i,r[i]);
- for(int i=1;i<=8;i++) addedge(i+16,i,r[i]-ans);
- addedge(0,24,ans);
- if(spfa(0,25)) right=ans,flag=false;
- else l=ans+1;
- }
- if(!flag) printf("%d\n",right);
- else printf("No Solution\n");
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=50005;
struct Edge
{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
void addedge(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool vis[maxn];
int cnt[maxn];
int dist[maxn];
bool spfa(int start,int n)
{
memset(vis,false,sizeof(vis));
memset(dist,-inf,sizeof(dist));
vis[start]=true;
dist[start]=0;
queue<int>que;
while(!que.empty()) que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]<dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
int num[30],r[30];
int main()
{
//freopen("cin.txt","r",stdin);
int t,ans,m;
scanf("%d",&t);
while(t--)
{
for(int i=1;i<=24;i++) scanf("%d",&r[i]);
for(int i=0;i<25;i++) num[i]=0;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
int tmp;
scanf("%d",&tmp);
num[tmp+1]++;///!!!
}
ans=1;
bool flag=true;
int l=0,right=m;
while(l<right)
{
for(int i=0;i<=24;i++) E[i].clear();
ans=(l+right)/2;
for(int i=1;i<=24;i++)
{
addedge(i-1,i,0);
addedge(i,i-1,-num[i]);
}
for(int i=8;i<=24;i++) addedge(i-8,i,r[i]);
for(int i=1;i<=8;i++) addedge(i+16,i,r[i]-ans);
addedge(0,24,ans);
if(spfa(0,25)) right=ans,flag=false;
else l=ans+1;
}
if(!flag) printf("%d\n",right);
else printf("No Solution\n");
}
return 0;
}
12、差分约束系统水题
hdu1531King
题意:给出asi+asi+1+…+asi+n大于或者小于ki 那么设从a[1]到a[i]的和为一个数,把它转化成最长路或者最短路都可做
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<vector>
- #include<queue>
- using namespace std;
- const int inf=0x3f3f3f3f;
- const int maxn=500;
- struct Edge
- {
- int v,cost;
- Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
- };
- vector<Edge>E[maxn];
- void addedge(int u,int v,int w)
- {
- E[u].push_back(Edge(v,w));
- }
- bool vis[maxn];
- int cnt[maxn];
- int dist[maxn];
- bool spfa(int start,int n)
- {
- memset(vis,false,sizeof(vis));
- memset(dist,-inf,sizeof(dist));
- vis[start]=true;
- dist[start]=0;
- queue<int>que;
- while(!que.empty()) que.pop();
- que.push(start);
- memset(cnt,0,sizeof(cnt));
- cnt[start]=1;
- while(!que.empty())
- {
- int u=que.front();
- que.pop();
- vis[u]=false;
- for(int i=0;i<E[u].size();i++)
- {
- int v=E[u][i].v;
- if(dist[v]<dist[u]+E[u][i].cost)
- {
- dist[v]=dist[u]+E[u][i].cost;
- if(!vis[v])
- {
- vis[v]=true;
- que.push(v);
- if(++cnt[v]>n) return false;
- }
- }
- }
- }
- return true;
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- int n,m,si,ni,ki;
- char oi[4];
- while(~scanf("%d",&n)&&n)
- {
- scanf("%d",&m);
- for(int i=0;i<=n+2;i++) E[i].clear();
- while(m--)
- {
- scanf("%d%d%s%d",&si,&ni,oi,&ki);
- if(oi[0]=='g') addedge(si-1,si+ni,ki+1);
- else addedge(si+ni,si-1,1-ki);
- }
- for(int i=0;i<=n;i++)addedge(n+1,i,0);
- if(spfa(n+1,n+2)) puts("lamentable kingdom");
- else puts("successful conspiracy");
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=500;
struct Edge
{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
void addedge(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool vis[maxn];
int cnt[maxn];
int dist[maxn];
bool spfa(int start,int n)
{
memset(vis,false,sizeof(vis));
memset(dist,-inf,sizeof(dist));
vis[start]=true;
dist[start]=0;
queue<int>que;
while(!que.empty()) que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]<dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
int main()
{
// freopen("cin.txt","r",stdin);
int n,m,si,ni,ki;
char oi[4];
while(~scanf("%d",&n)&&n)
{
scanf("%d",&m);
for(int i=0;i<=n+2;i++) E[i].clear();
while(m--)
{
scanf("%d%d%s%d",&si,&ni,oi,&ki);
if(oi[0]=='g') addedge(si-1,si+ni,ki+1);
else addedge(si+ni,si-1,1-ki);
}
for(int i=0;i<=n;i++)addedge(n+1,i,0);
if(spfa(n+1,n+2)) puts("lamentable kingdom");
else puts("successful conspiracy");
}
return 0;
}
13、差分约束系统较难题 :跳房子
hdu3440House Man【差分约束系统】
题意:由左至右一堆高矮不同的小房子,只能从左向右水平距离不超过d个房子,问水平最多走多远做法:先为存有(点序号,房子高度)的结构体数组排序,枚举相邻高度的房子,为其加"d"的边,跑最短路。注意最终求的是最左边点(起点)和最右边点(终点)
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<vector>
- #include<queue>
- #include<algorithm>
- using namespace std;
- const int inf=0x3f3f3f3f;
- const int maxn=1005;
- struct Edge
- {
- int v,cost;
- Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
- };
- vector<Edge>E[maxn];
- void addedge(int u,int v,int w)
- {
- E[u].push_back(Edge(v,w));
- }
- bool vis[maxn];
- int cnt[maxn];
- int dist[maxn];
- bool spfa(int start,int n)
- {
- memset(vis,false,sizeof(vis));
- memset(dist,inf,sizeof(dist));
- vis[start]=true;
- dist[start]=0;
- queue<int>que;
- while(!que.empty()) que.pop();
- que.push(start);
- memset(cnt,0,sizeof(cnt));
- cnt[start]=1;
- while(!que.empty())
- {
- int u=que.front();
- que.pop();
- vis[u]=false;
- for(int i=0;i<E[u].size();i++)
- {
- int v=E[u][i].v;
- if(dist[v]>dist[u]+E[u][i].cost)
- {
- dist[v]=dist[u]+E[u][i].cost;
- if(!vis[v])
- {
- vis[v]=true;
- que.push(v);
- if(++cnt[v]>n) return false;
- }
- }
- }
- }
- return true;
- }
- struct node
- {
- int val,pos;
- }nt[maxn];
- bool cmp(node a,node b)
- {
- return a.val<b.val;
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- int t,n,d,cas=1;
- scanf("%d",&t);
- while(t--)
- {
- scanf("%d%d",&n,&d);
- for(int i=1;i<=n;i++) scanf("%d",&nt[i].val),nt[i].pos=i;
- sort(nt+1,nt+1+n,cmp);
- for(int i=0;i<=n;i++) E[i].clear();
- for(int i=1;i<n;i++)
- {
- addedge(i+1,i,-1);
- if(nt[i].pos<nt[i+1].pos)
- addedge(nt[i].pos,nt[i+1].pos,d);
- else addedge(nt[i+1].pos,nt[i].pos,d);
- }
- printf("Case %d: ",cas++);
- int minn,maxn;
- if(nt[1].pos<nt[n].pos)minn=nt[1].pos,maxn=nt[n].pos;
- else minn=nt[n].pos,maxn=nt[1].pos;
- if(!spfa(minn,n)) printf("-1\n");
- else printf("%d\n",dist[maxn]);
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1005;
struct Edge
{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
void addedge(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool vis[maxn];
int cnt[maxn];
int dist[maxn];
bool spfa(int start,int n)
{
memset(vis,false,sizeof(vis));
memset(dist,inf,sizeof(dist));
vis[start]=true;
dist[start]=0;
queue<int>que;
while(!que.empty()) que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]>dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
struct node
{
int val,pos;
}nt[maxn];
bool cmp(node a,node b)
{
return a.val<b.val;
}
int main()
{
// freopen("cin.txt","r",stdin);
int t,n,d,cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++) scanf("%d",&nt[i].val),nt[i].pos=i;
sort(nt+1,nt+1+n,cmp);
for(int i=0;i<=n;i++) E[i].clear();
for(int i=1;i<n;i++)
{
addedge(i+1,i,-1);
if(nt[i].pos<nt[i+1].pos)
addedge(nt[i].pos,nt[i+1].pos,d);
else addedge(nt[i+1].pos,nt[i].pos,d);
}
printf("Case %d: ",cas++);
int minn,maxn;
if(nt[1].pos<nt[n].pos)minn=nt[1].pos,maxn=nt[n].pos;
else minn=nt[n].pos,maxn=nt[1].pos;
if(!spfa(minn,n)) printf("-1\n");
else printf("%d\n",dist[maxn]);
}
return 0;
}
14、spfa最短路+tsp状压
题意:n*n的矩阵,每一个格子都有相应的花费,k个宝藏的位置。从任意边界进入任意边界出去。求出得到所有宝藏的最小花费。
思路:将边界作为0点。bfs求出宝藏之间以及宝藏与0点的最短距离。一次TSP,在图中跑一次回路,从起点0回到起点,得到最小花费。
附上的也是一个 13级妹子的代码,比我的那份写的好看太多
- #include <iostream>
- #include <cstdio>
- #include <queue>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- const int INF = 0x3f3f3f3f;
- int a[205][205], d[205][205];
- int x[205], y[205], dp[1<<15][15];
- bool v[205][205];
- struct node {
- int x, y, c;
- node(int xx, int yy, int cc) {
- x = xx; y = yy; c = cc;
- }
- bool operator <(const node & A) const {
- return c > A.c;
- }
- };
- int dx[]={1, -1, 0, 0}, dy[]={0, 0, 1, -1};
- int n, m, k;
- bool ok(int x, int y)
- {
- if(x < 0 || y < 0 || x >= n || y >= m || a[x][y] == -1) {
- return false;
- }
- return true;
- }
- void bfs(int s, int t)
- {
- priority_queue<node> que;
- memset(v, 0, sizeof(v));
- que.push(node(x[s], y[s], 0));
- v[x[s]][y[s]] = 1;
- int c = 0;
- while(!que.empty()) {
- node e = que.top(); que.pop();
- if(e.x == x[t] && e.y == y[t]) {
- c = e.c - a[x[t]][y[t]];
- }
- for(int i = 0; i < 4; ++i) {
- int nx = e.x+dx[i], ny = e.y+dy[i];
- if(v[nx][ny] || a[nx][ny] == -1)
- continue;
- if(nx < 0 || ny < 0 || nx >= n || ny >= m) {
- d[s][0] = min(d[s][0], e.c);
- d[0][s] = min(d[0][s], e.c);
- continue;
- }
- v[nx][ny] = 1;
- que.push(node(nx, ny, e.c+a[nx][ny]));
- }
- }
- if(s != t) {
- d[s][t] = c;
- d[t][s] = c;
- }
- }
- void deal_p_p()
- {
- memset(d, 0x3f, sizeof(d));
- for(int i = 1; i <= k; ++i) {
- for(int j = 1; j <= k; ++j) {
- //while(!que.empty()) que.pop();
- bfs(i, j);
- }
- }
- }
- int solve()
- {
- memset(dp, 0x3f, sizeof(dp));
- int nk = k+1;
- dp[(1<<nk)-1][0] = 0;
- for(int s = (1<<nk)-2; s >= 0; --s) {
- for(int v = 0; v < nk; ++v) {
- for(int u = 0; u < nk; ++u) {
- if(!(s>>u &1)) {
- dp[s][v] = min(dp[s][v], dp[s|1<<u][u]+d[v][u]);
- }
- }
- }
- }
- return dp[0][0];
- }
- int main()
- {
- //freopen("in", "r", stdin);
- int T;
- scanf("%d", &T);
- while(T--) {
- scanf("%d%d", &n, &m);
- memset(a, 0, sizeof(a));
- for(int i = 0; i < n; ++i) {
- for(int j = 0; j < m; ++j) {
- scanf("%d", &a[i][j]);
- }
- }
- int Sum = 0;
- scanf("%d", &k);
- memset(x, 0, sizeof(x));
- memset(y, 0, sizeof(y));
- for(int i = 1; i <= k; ++i) {
- scanf("%d%d", &x[i], &y[i]);
- Sum += a[x[i]][y[i]];
- }
- deal_p_p();
- if(k == 1) {
- if(d[1][0] == INF) {
- printf("0\n");
- }
- else printf("%d\n", 2*d[1][0]+a[x[1]][y[1]]);
- }
- else {
- int ans = solve();
- if(ans == INF) printf("0\n");
- else printf("%d\n", ans+Sum);
- }
- }
- return 0;
- }
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int a[205][205], d[205][205];
int x[205], y[205], dp[1<<15][15];
bool v[205][205];
struct node {
int x, y, c;
node(int xx, int yy, int cc) {
x = xx; y = yy; c = cc;
}
bool operator <(const node & A) const {
return c > A.c;
}
};
int dx[]={1, -1, 0, 0}, dy[]={0, 0, 1, -1};
int n, m, k;
bool ok(int x, int y)
{
if(x < 0 || y < 0 || x >= n || y >= m || a[x][y] == -1) {
return false;
}
return true;
}
void bfs(int s, int t)
{
priority_queue<node> que;
memset(v, 0, sizeof(v));
que.push(node(x[s], y[s], 0));
v[x[s]][y[s]] = 1;
int c = 0;
while(!que.empty()) {
node e = que.top(); que.pop();
if(e.x == x[t] && e.y == y[t]) {
c = e.c - a[x[t]][y[t]];
}
for(int i = 0; i < 4; ++i) {
int nx = e.x+dx[i], ny = e.y+dy[i];
if(v[nx][ny] || a[nx][ny] == -1)
continue;
if(nx < 0 || ny < 0 || nx >= n || ny >= m) {
d[s][0] = min(d[s][0], e.c);
d[0][s] = min(d[0][s], e.c);
continue;
}
v[nx][ny] = 1;
que.push(node(nx, ny, e.c+a[nx][ny]));
}
}
if(s != t) {
d[s][t] = c;
d[t][s] = c;
}
}
void deal_p_p()
{
memset(d, 0x3f, sizeof(d));
for(int i = 1; i <= k; ++i) {
for(int j = 1; j <= k; ++j) {
//while(!que.empty()) que.pop();
bfs(i, j);
}
}
}
int solve()
{
memset(dp, 0x3f, sizeof(dp));
int nk = k+1;
dp[(1<<nk)-1][0] = 0;
for(int s = (1<<nk)-2; s >= 0; --s) {
for(int v = 0; v < nk; ++v) {
for(int u = 0; u < nk; ++u) {
if(!(s>>u &1)) {
dp[s][v] = min(dp[s][v], dp[s|1<<u][u]+d[v][u]);
}
}
}
}
return dp[0][0];
}
int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
memset(a, 0, sizeof(a));
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
scanf("%d", &a[i][j]);
}
}
int Sum = 0;
scanf("%d", &k);
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for(int i = 1; i <= k; ++i) {
scanf("%d%d", &x[i], &y[i]);
Sum += a[x[i]][y[i]];
}
deal_p_p();
if(k == 1) {
if(d[1][0] == INF) {
printf("0\n");
}
else printf("%d\n", 2*d[1][0]+a[x[1]][y[1]]);
}
else {
int ans = solve();
if(ans == INF) printf("0\n");
else printf("%d\n", ans+Sum);
}
}
return 0;
}
15、取消一点使得最短路有最大值
hdu5137How Many Maos Does the Guanxi Worth
题意:暴发户给孩子办关系升学,需要一个人找一个人,人情钱都是这货出,你要劝说其中一个人不去帮忙使得暴发户花钱最多枚举所有点,逐次跑最短路即可
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- using namespace std;
- const int maxn=33;
- const int inf=0x3f3f3f3f;
- bool vis[maxn];
- int pre[maxn],lowcost[maxn],cost[maxn][maxn];
- void dijkstra(int n,int beg)
- {
- for(int i=0;i<n;i++)
- {
- lowcost[i]=inf;vis[i]=false;pre[i]=-1;
- }
- lowcost[beg]=0;
- for(int j=0;j<n;j++)
- {
- int k=-1;
- int Min=inf;
- for(int i=0;i<n;i++)
- if(!vis[i]&&lowcost[i]<Min)
- {
- Min=lowcost[i];
- k=i;
- }
- if(k==-1)break;
- vis[k]=true;
- for(int i=0;i<n;i++)
- if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i])
- {
- lowcost[i]=lowcost[k]+cost[k][i];
- pre[i]=k;
- }
- }
- }
- int temp[maxn];
- int main()
- {
- // freopen("cin.txt","r",stdin);
- int n,m;
- while(~scanf("%d%d",&n,&m)&&n&&m)
- {
- memset(cost,inf,sizeof(cost));
- for(int i=0;i<m;i++)
- {
- int a,b,c;
- scanf("%d%d%d",&a,&b,&c);
- a--;b--;
- if(c>cost[a][b]) continue;
- cost[a][b]=cost[b][a]=c;
- }
- int ans=0;
- for(int i=1;i<n-1;i++)
- {
- for(int j=0;j<=n-1;j++)
- {
- temp[j]=cost[i][j];
- cost[i][j]=cost[j][i]=inf;
- }
- dijkstra(n,0);
- if(lowcost[n-1]>ans) ans=lowcost[n-1];
- for(int j=0;j<n;j++)
- cost[i][j]=cost[j][i]=temp[j];
- }
- if(ans<inf) printf("%d\n",ans);
- else printf("Inf\n");
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=33;
const int inf=0x3f3f3f3f;
bool vis[maxn];
int pre[maxn],lowcost[maxn],cost[maxn][maxn];
void dijkstra(int n,int beg)
{
for(int i=0;i<n;i++)
{
lowcost[i]=inf;vis[i]=false;pre[i]=-1;
}
lowcost[beg]=0;
for(int j=0;j<n;j++)
{
int k=-1;
int Min=inf;
for(int i=0;i<n;i++)
if(!vis[i]&&lowcost[i]<Min)
{
Min=lowcost[i];
k=i;
}
if(k==-1)break;
vis[k]=true;
for(int i=0;i<n;i++)
if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i])
{
lowcost[i]=lowcost[k]+cost[k][i];
pre[i]=k;
}
}
}
int temp[maxn];
int main()
{
// freopen("cin.txt","r",stdin);
int n,m;
while(~scanf("%d%d",&n,&m)&&n&&m)
{
memset(cost,inf,sizeof(cost));
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
a--;b--;
if(c>cost[a][b]) continue;
cost[a][b]=cost[b][a]=c;
}
int ans=0;
for(int i=1;i<n-1;i++)
{
for(int j=0;j<=n-1;j++)
{
temp[j]=cost[i][j];
cost[i][j]=cost[j][i]=inf;
}
dijkstra(n,0);
if(lowcost[n-1]>ans) ans=lowcost[n-1];
for(int j=0;j<n;j++)
cost[i][j]=cost[j][i]=temp[j];
}
if(ans<inf) printf("%d\n",ans);
else printf("Inf\n");
}
return 0;
}
16、最短路反向建图(酋长是终点不是起点,最开始所有点前面再加一个源点)枚举等级区间依次跑最短路即可
poj1062昂贵的聘礼
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- using namespace std;
- const int maxn=133;
- const int inf=0x3f3f3f3f;
- bool vis[maxn];
- int pre[maxn],lowcost[maxn],cost[maxn][maxn],val[maxn],rank[maxn];
- void dijkstra(int cost[][maxn],int n,int beg)
- {
- for(int i=0;i<n;i++)
- {
- lowcost[i]=inf;vis[i]=false;pre[i]=-1;
- }
- lowcost[beg]=0;
- for(int j=0;j<n;j++)
- {
- int k=-1;
- int Min=inf;
- for(int i=0;i<n;i++)
- if(!vis[i]&&lowcost[i]<Min)
- {
- Min=lowcost[i];
- k=i;
- }
- if(k==-1)break;
- vis[k]=true;
- for(int i=0;i<n;i++)
- if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i])
- {
- lowcost[i]=lowcost[k]+cost[k][i];
- pre[i]=k;
- }
- }
- }
- int tmp[maxn][maxn];
- int main()
- {
- freopen("cin.txt","r",stdin);
- int m,n;
- while(~scanf("%d%d",&m,&n))
- {
- memset(cost,inf,sizeof(cost));
- int maxn=0,minn=inf;
- for(int i=0;i<n;i++)
- {
- int x;
- scanf("%d%d%d",&cost[n][i],&rank[i],&x);
- if(rank[i]>maxn)maxn=rank[i];
- if(rank[i]<minn)minn=rank[i];
- while(x--)
- {
- int t,v;
- scanf("%d%d",&t,&v);t--;
- if(v<cost[i][t]) cost[i][t]=v;
- }
- }
- int ans=inf;
- for(int k=max(0,rank[0]-m);k<=rank[0]+m;k++)
- {
- for(int i=0;i<n;i++)
- for(int j=0;j<n;j++)
- {
- if(rank[i]>=k&&rank[i]<=k+m&&rank[j]>=k&&rank[j]<=k+m)
- tmp[i][j]=cost[i][j];
- else tmp[i][j]=inf;
- }
- dijkstra(tmp,n,0);
- for(int i=0;i<n;i++)
- if(ans>lowcost[i]+cost[n][i])
- ans=lowcost[i]+cost[n][i];
- }
- printf("%d\n",ans);
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=133;
const int inf=0x3f3f3f3f;
bool vis[maxn];
int pre[maxn],lowcost[maxn],cost[maxn][maxn],val[maxn],rank[maxn];
void dijkstra(int cost[][maxn],int n,int beg)
{
for(int i=0;i<n;i++)
{
lowcost[i]=inf;vis[i]=false;pre[i]=-1;
}
lowcost[beg]=0;
for(int j=0;j<n;j++)
{
int k=-1;
int Min=inf;
for(int i=0;i<n;i++)
if(!vis[i]&&lowcost[i]<Min)
{
Min=lowcost[i];
k=i;
}
if(k==-1)break;
vis[k]=true;
for(int i=0;i<n;i++)
if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i])
{
lowcost[i]=lowcost[k]+cost[k][i];
pre[i]=k;
}
}
}
int tmp[maxn][maxn];
int main()
{
freopen("cin.txt","r",stdin);
int m,n;
while(~scanf("%d%d",&m,&n))
{
memset(cost,inf,sizeof(cost));
int maxn=0,minn=inf;
for(int i=0;i<n;i++)
{
int x;
scanf("%d%d%d",&cost[n][i],&rank[i],&x);
if(rank[i]>maxn)maxn=rank[i];
if(rank[i]<minn)minn=rank[i];
while(x--)
{
int t,v;
scanf("%d%d",&t,&v);t--;
if(v<cost[i][t]) cost[i][t]=v;
}
}
int ans=inf;
for(int k=max(0,rank[0]-m);k<=rank[0]+m;k++)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(rank[i]>=k&&rank[i]<=k+m&&rank[j]>=k&&rank[j]<=k+m)
tmp[i][j]=cost[i][j];
else tmp[i][j]=inf;
}
dijkstra(tmp,n,0);
for(int i=0;i<n;i++)
if(ans>lowcost[i]+cost[n][i])
ans=lowcost[i]+cost[n][i];
}
printf("%d\n",ans);
}
return 0;
}
17、送餐来回的最短距离
看到这个题的时候想到上面的第7题了,然而第7题不需要每个点都遍历一遍,而这个题需要,所以这个是需要用状压的tsp的
poj3311 Hie with the Pie【floyd最短路+状态压缩】
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- using namespace std;
- int dp[1<<11][20],n,num[11][11];
- int min(int a,int b){if(a<b)return a;return b;}
- int judge(int s)
- {
- int num=0;
- while(s)
- {
- if(s&1)num++;
- s>>=1;
- }
- return num;
- }
- int dist[11][11];
- void init()
- {
- for(int i=0;i<n;i++)
- for(int j=0;j<n;j++)
- {
- dist[i][j]=num[i][j];
- }
- for(int i=0;i<n;i++)
- for(int j=0;j<n;j++)
- for(int k=0;k<n;k++)
- if(dist[j][i]+dist[i][k]<dist[j][k])
- dist[j][k]=dist[j][i]+dist[i][k];
- for(int i=0;i<n;i++)
- for(int j=0;j<n;j++);
- // printf("i=%d,j=%d,dist=%d\n",i,j,dist[i][j]);
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- while(~scanf("%d",&n)&&n)
- {
- for(int i=0;i<=n;i++)
- for(int j=0;j<=n;j++)
- scanf("%d",&num[i][j]);
- memset(dp,0x3f3f3f3f,sizeof(dp));
- dp[0][0]=0;
- n++;//have n+1 points
- init();
- for(int i=0;i<n;i++)//n points
- dp[1<<i|1][i]=dist[0][i];
- // for(int i=0;i<(1<<n)-1;i++) if(dp[i]!=0x3f3f3f3f)printf("i=%d dp=%d ",i,dp[i]);
- int ans=0x3f3f3f3f;
- for(int i=1;i<(1<<n)-1;i++)//now
- {
- for(int j=0;j<n;j++)//not exist
- {
- if(i&(1<<j)) continue;
- for(int k=0;k<n;k++)//exist
- {
- if(j==k) continue;
- if(i&(1<<k))
- {
- dp[1<<j|i][j]=min(dp[i][k]+dist[k][j],dp[1<<j|i][j]);
- if(judge(1<<j|i)==n)
- ans=min(ans,dp[1<<j|i][j]+dist[j][0]);
- }
- }
- }
- }
- printf("%d\n",ans);
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[1<<11][20],n,num[11][11];
int min(int a,int b){if(a<b)return a;return b;}
int judge(int s)
{
int num=0;
while(s)
{
if(s&1)num++;
s>>=1;
}
return num;
}
int dist[11][11];
void init()
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
dist[i][j]=num[i][j];
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
if(dist[j][i]+dist[i][k]<dist[j][k])
dist[j][k]=dist[j][i]+dist[i][k];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++);
// printf("i=%d,j=%d,dist=%d\n",i,j,dist[i][j]);
}
int main()
{
// freopen("cin.txt","r",stdin);
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
scanf("%d",&num[i][j]);
memset(dp,0x3f3f3f3f,sizeof(dp));
dp[0][0]=0;
n++;//have n+1 points
init();
for(int i=0;i<n;i++)//n points
dp[1<<i|1][i]=dist[0][i];
// for(int i=0;i<(1<<n)-1;i++) if(dp[i]!=0x3f3f3f3f)printf("i=%d dp=%d ",i,dp[i]);
int ans=0x3f3f3f3f;
for(int i=1;i<(1<<n)-1;i++)//now
{
for(int j=0;j<n;j++)//not exist
{
if(i&(1<<j)) continue;
for(int k=0;k<n;k++)//exist
{
if(j==k) continue;
if(i&(1<<k))
{
dp[1<<j|i][j]=min(dp[i][k]+dist[k][j],dp[1<<j|i][j]);
if(judge(1<<j|i)==n)
ans=min(ans,dp[1<<j|i][j]+dist[j][0]);
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
18、 建全国的路的一部分,依旧要求联通,但是首都到各个城市的最短距离不变的前提下求最小花费
Aizu 2249Road Construction 单源最短路变形 spfa模板改写
既然是首都到各地的距离最短前提下求最小花费,那么松弛操作当距离相等的时候压入花费小的就可以啦- #include <stdio.h>
- #include <string.h>
- #include <queue>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- const int maxn=10050;
- const int maxe=2005000;
- const int INF=1e9;
- struct note
- {
- int to;
- int w;
- int c;
- int next;
- };
- note edge[maxe];
- int head[maxn];
- int ip;
- void init()
- {
- memset(head,-1,sizeof(head));
- ip=0;
- }
- void addedge(int u,int v,int w,int c)
- {
- edge[ip].to=v;
- edge[ip].c=c;
- edge[ip].w=w;
- edge[ip].next=head[u];
- head[u]=ip++;
- }
- int cost[maxn];
- int dis[maxn];
- bool vis[maxn];
- queue<int>q;
- void spfa(int s,int n)
- {
- while(!q.empty())q.pop();
- for(int i=1;i<=n;i++)
- cost[i]=dis[i]=INF;
- memset(vis,false,sizeof(vis));
- dis[s]=0;
- cost[s]=0;
- vis[s]=true;
- q.push(s);
- while(!q.empty())
- {
- int u=q.front();
- q.pop();
- vis[u]=false;
- for(int i=head[u];i!=-1;i=edge[i].next)
- {
- int to=edge[i].to;
- int val=edge[i].w;
- if(dis[to]>dis[u]+val||(dis[to]==dis[u]+val&&cost[to]>edge[i].c))//有多条最短路时,取花费最小的
- {
- dis[to]=dis[u]+val;
- cost[to]=edge[i].c;
- if(!vis[to])
- {
- q.push(to);
- vis[to]=true;
- }
- }
- }
- }
- }
- int main()
- {
- // freopen("cin.txt","r",stdin);
- int n,m;
- int u,v,w,c;
- while(~scanf("%d%d",&n,&m))
- {
- if(n==0&&m==0) break;
- init();
- for(int i=0;i<m;i++)
- {
- scanf("%d%d%d%d",&u,&v,&c,&w);
- addedge(u,v,c,w);
- addedge(v,u,c,w);
- }
- spfa(1,n);
- int ans=0;
- for(int i=1;i<=n;i++)
- ans+=cost[i];
- printf("%d\n",ans);
- }
- return 0;
- }
#include <stdio.h>
#include <string.h>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=10050;
const int maxe=2005000;
const int INF=1e9;
struct note
{
int to;
int w;
int c;
int next;
};
note edge[maxe];
int head[maxn];
int ip;
void init()
{
memset(head,-1,sizeof(head));
ip=0;
}
void addedge(int u,int v,int w,int c)
{
edge[ip].to=v;
edge[ip].c=c;
edge[ip].w=w;
edge[ip].next=head[u];
head[u]=ip++;
}
int cost[maxn];
int dis[maxn];
bool vis[maxn];
queue<int>q;
void spfa(int s,int n)
{
while(!q.empty())q.pop();
for(int i=1;i<=n;i++)
cost[i]=dis[i]=INF;
memset(vis,false,sizeof(vis));
dis[s]=0;
cost[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
int val=edge[i].w;
if(dis[to]>dis[u]+val||(dis[to]==dis[u]+val&&cost[to]>edge[i].c))//有多条最短路时,取花费最小的
{
dis[to]=dis[u]+val;
cost[to]=edge[i].c;
if(!vis[to])
{
q.push(to);
vis[to]=true;
}
}
}
}
}
int main()
{
// freopen("cin.txt","r",stdin);
int n,m;
int u,v,w,c;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
init();
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d",&u,&v,&c,&w);
addedge(u,v,c,w);
addedge(v,u,c,w);
}
spfa(1,n);
int ans=0;
for(int i=1;i<=n;i++)
ans+=cost[i];
printf("%d\n",ans);
}
return 0;
}
19、 差分约束系统
题意:对于给定有向图,定义一种操作:对于选定的某一点,进入这个点的所有边权都减去d,从这个点出去的所有边权都加上d。经过一系列的操作,使得所有边权的最小值达到最大,需保证这个最值是正数
by the way Spfa要是最开始不加超级源点,就要把所有的点都压入队列
这么看来就和上面的题一样啦
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<vector>
- #include<queue>
- using namespace std;
- const int inf=0x3f3f;
- const int maxn=505;
- int n,m;
- struct Edge
- {
- int v,cost;
- Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
- };
- vector<Edge>E[maxn];
- void addedge(int u,int v,int w)
- {
- E[u].push_back(Edge(v,w));
- }
- bool vis[maxn];
- int cnt[maxn];
- int dist[maxn];
- bool spfa(int start,int n)
- {
- memset(vis,false,sizeof(vis));
- memset(dist,inf,sizeof(dist));
- vis[start]=true;
- dist[start]=0;
- queue<int>que;
- while(!que.empty()) que.pop();
- que.push(start);
- memset(cnt,0,sizeof(cnt));
- cnt[start]=1;
- while(!que.empty())
- {
- int u=que.front();
- que.pop();
- vis[u]=false;
- for(int i=0;i<E[u].size();i++)
- {
- int v=E[u][i].v;
- if(dist[v]>dist[u]+E[u][i].cost)
- {
- dist[v]=dist[u]+E[u][i].cost;
- if(!vis[v])
- {
- vis[v]=true;
- que.push(v);
- if(++cnt[v]>n) return false;
- }
- }
- }
- }
- return true;
- }
- bool judge(int x)
- {
- // cout<<"rrr"<<endl;
- for(int i=1;i<=n;i++)
- {
- for(int j=0;j<E[i].size();j++)
- E[i][j].cost-=x;
- }
- bool flag=spfa(0,n);
- for(int i=1;i<=n;i++)
- {
- for(int j=0;j<E[i].size();j++)
- E[i][j].cost+=x;
- }
- return flag;
- }
- int main()
- {
- //freopen("cin.txt","r",stdin);
- // int cas=1;
- // scanf("%d",&t);
- while(~scanf("%d%d",&n,&m))
- {
- // printf("Case #%d: ",cas++);
- for(int i=0;i<=n;i++) E[i].clear();
- // memset(head,-1,sizeof(head));
- int l=1,mid,r=-inf;
- while(m--)
- {
- int a,b;
- int c;
- scanf("%d%d%d",&a,&b,&c);
- addedge(a,b,c);
- if(c>r)r=c;
- }
- for(int i=1;i<=n;i++)addedge(0,i,0);
- // cout<<"rrr"<<endl;
- // printf("r=%d\n",r);
- if(judge(r))
- {
- printf("Infinite\n");
- continue;
- }
- else if(!judge(1))
- {
- puts("No Solution");
- continue;
- }
- int ans;
- while(l<=r)
- {
- mid=(l+r)/2;
- // cout<<mid<<endl;
- // printf("l=%d,mid=%d,r=%d ",l,mid,r);
- if(judge(mid)) ans=mid,l=mid+1;
- else {r=mid-1;}
- // printf("l=%d,mid=%d,r=%d,ans=%d\n",l,mid,r,ans);
- }
- printf("%d\n",ans);
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int inf=0x3f3f;
const int maxn=505;
int n,m;
struct Edge
{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
void addedge(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool vis[maxn];
int cnt[maxn];
int dist[maxn];
bool spfa(int start,int n)
{
memset(vis,false,sizeof(vis));
memset(dist,inf,sizeof(dist));
vis[start]=true;
dist[start]=0;
queue<int>que;
while(!que.empty()) que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]>dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
bool judge(int x)
{
// cout<<"rrr"<<endl;
for(int i=1;i<=n;i++)
{
for(int j=0;j<E[i].size();j++)
E[i][j].cost-=x;
}
bool flag=spfa(0,n);
for(int i=1;i<=n;i++)
{
for(int j=0;j<E[i].size();j++)
E[i][j].cost+=x;
}
return flag;
}
int main()
{
//freopen("cin.txt","r",stdin);
// int cas=1;
// scanf("%d",&t);
while(~scanf("%d%d",&n,&m))
{
// printf("Case #%d: ",cas++);
for(int i=0;i<=n;i++) E[i].clear();
// memset(head,-1,sizeof(head));
int l=1,mid,r=-inf;
while(m--)
{
int a,b;
int c;
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
if(c>r)r=c;
}
for(int i=1;i<=n;i++)addedge(0,i,0);
// cout<<"rrr"<<endl;
// printf("r=%d\n",r);
if(judge(r))
{
printf("Infinite\n");
continue;
}
else if(!judge(1))
{
puts("No Solution");
continue;
}
int ans;
while(l<=r)
{
mid=(l+r)/2;
// cout<<mid<<endl;
// printf("l=%d,mid=%d,r=%d ",l,mid,r);
if(judge(mid)) ans=mid,l=mid+1;
else {r=mid-1;}
// printf("l=%d,mid=%d,r=%d,ans=%d\n",l,mid,r,ans);
}
printf("%d\n",ans);
}
return 0;
}
20、二分找负环
一样的题:给定有向带权图,求最小环的值。二分找最小值,边权都减去这个数
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<vector>
- using namespace std;
- const double inf=0x3f3f3f3f;
- const int maxn=100;
- int n,m,t;
- double dist[maxn];
- struct Edge
- {
- int u,v;
- double cost;
- Edge(int _u=0,int _v=0,double _cost=0):u(_u),v(_v),cost(_cost){}
- };
- vector<Edge>E;
- bool bellman(int start,int n)
- {
- for(int i=1;i<=n;i++)dist[i]=inf;
- dist[start]=0;
- for(int i=1;i<n;i++)
- {
- bool flag=false;
- for(int j=0;j<E.size();j++)
- {
- int u=E[j].u;
- int v=E[j].v;
- double cost=E[j].cost;
- if(dist[v]>dist[u]+cost)
- {
- dist[v]=dist[u]+cost;
- flag=true;
- }
- }
- if(!flag)return true;
- }
- for(int j=0;j<E.size();j++)
- if(dist[E[j].v]>dist[E[j].u]+E[j].cost)
- return false;
- return true;
- }
- bool judge(double x)
- {
- for(int i=0;i<E.size();i++) E[i].cost-=x;
- bool flag=bellman(1,n);
- for(int i=0;i<E.size();i++) E[i].cost+=x;
- return flag;
- }
- int main()
- {
- //freopen("cin.txt","r",stdin);
- int cas=1;
- scanf("%d",&t);
- while(t--)
- {
- scanf("%d%d",&n,&m);
- printf("Case #%d: ",cas++);
- E.clear();
- double r=0.0;
- while(m--)
- {
- int a,b;
- double c;
- scanf("%d%d%lf",&a,&b,&c);
- E.push_back(Edge(a,b,c));
- if(c>r)r=c;
- }
- // printf("r=%lf\n",r);
- if(judge(r+1))
- {
- printf("No cycle found.\n");
- continue;
- }
- double l=0.0,mid;
- while(r-l>=0.0001)
- {
- mid=(l+r)/2;
- for(int i=0;i<E.size();i++) E[i].cost-=mid;
- if(bellman(1,n)) l=mid;
- else r=mid;
- for(int i=0;i<E.size();i++) E[i].cost+=mid;
- }
- printf("%.2lf\n",r);
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const double inf=0x3f3f3f3f;
const int maxn=100;
int n,m,t;
double dist[maxn];
struct Edge
{
int u,v;
double cost;
Edge(int _u=0,int _v=0,double _cost=0):u(_u),v(_v),cost(_cost){}
};
vector<Edge>E;
bool bellman(int start,int n)
{
for(int i=1;i<=n;i++)dist[i]=inf;
dist[start]=0;
for(int i=1;i<n;i++)
{
bool flag=false;
for(int j=0;j<E.size();j++)
{
int u=E[j].u;
int v=E[j].v;
double cost=E[j].cost;
if(dist[v]>dist[u]+cost)
{
dist[v]=dist[u]+cost;
flag=true;
}
}
if(!flag)return true;
}
for(int j=0;j<E.size();j++)
if(dist[E[j].v]>dist[E[j].u]+E[j].cost)
return false;
return true;
}
bool judge(double x)
{
for(int i=0;i<E.size();i++) E[i].cost-=x;
bool flag=bellman(1,n);
for(int i=0;i<E.size();i++) E[i].cost+=x;
return flag;
}
int main()
{
//freopen("cin.txt","r",stdin);
int cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
printf("Case #%d: ",cas++);
E.clear();
double r=0.0;
while(m--)
{
int a,b;
double c;
scanf("%d%d%lf",&a,&b,&c);
E.push_back(Edge(a,b,c));
if(c>r)r=c;
}
// printf("r=%lf\n",r);
if(judge(r+1))
{
printf("No cycle found.\n");
continue;
}
double l=0.0,mid;
while(r-l>=0.0001)
{
mid=(l+r)/2;
for(int i=0;i<E.size();i++) E[i].cost-=mid;
if(bellman(1,n)) l=mid;
else r=mid;
for(int i=0;i<E.size();i++) E[i].cost+=mid;
}
printf("%.2lf\n",r);
}
return 0;
}
21、
hdu4786Fibonacci Tree【kruskal最小生成树】
给定无向图每个边要么是白色,要么是黑色。求生成树的白边个数能否是斐波那契数。其实应该能想到的,让白边是1,黑边是0,求最大生成树和最小生成树。看中间范围是否有斐波那契数。
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int maxn=200005;
- const int maxm=200005;
- int F[maxn];
- struct Edge
- {
- int u,v,w;
- }edge[maxm];
- int tol;
- void addedge(int u,int v,int w)
- {
- edge[tol].v=v;
- edge[tol].u=u;
- edge[tol++].w=w;
- }
- bool cmp(Edge a,Edge b)
- {
- return a.w<b.w;
- }
- bool cmp2(Edge a,Edge b)
- {
- return a.w>b.w;
- }
- int fnd(int x)
- {
- return x==F[x]?x:F[x]=fnd(F[x]);
- }
- int kruskal(int n)
- {
- for(int i=1;i<=n;i++) F[i]=i;
- // sort(edge,edge+tol,cmp);
- int cnt=0;
- int ans=0;
- for(int i=0;i<tol;i++)
- {
- int u=edge[i].u;
- int v=edge[i].v;
- int w=edge[i].w;
- int a=fnd(u);
- int b=fnd(v);
- if(a!=b)
- {
- ans+=w;
- F[b]=a;
- cnt++;
- }
- if(cnt==n-1)break;
- }
- if(cnt<n-1)return -1;
- return ans;
- }
- int num[100],cnt;
- void init()
- {
- num[0]=0;num[1]=1;num[2]=2;num[3]=3;
- cnt=4;
- while(num[cnt-1]<=100005)
- {
- num[cnt]=num[cnt-1]+num[cnt-2];
- cnt++;
- // cout<<num[cnt-1]<<endl;
- }
- }
- int main()
- {
- //freopen("cin.txt","r",stdin);
- int t,n,m,cas=1;
- scanf("%d",&t);
- init();
- while(t--)
- {
- scanf("%d%d",&n,&m);
- tol=0;
- while(m--)
- {
- int u,v,w;
- scanf("%d%d%d",&u,&v,&w);
- addedge(u,v,w);
- addedge(v,u,w);///!!!
- }
- printf("Case #%d: ",cas++);
- sort(edge,edge+tol,cmp);
- int small=kruskal(n);
- bool ff=true;
- sort(edge,edge+tol,cmp2);
- int big=kruskal(n);
- // printf("s=%d,b=%d\n",small,big);
- if(small==-1||big==-1)
- {
- puts("No");
- continue;
- }
- bool flag=false;
- for(int i=1;i<=23;i++)
- {
- if(num[i]>=small&&num[i]<=big)
- {
- flag=true;
- break;
- }
- }
- if(flag) printf("Yes\n");
- else printf("No\n");
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
const int maxm=200005;
int F[maxn];
struct Edge
{
int u,v,w;
}edge[maxm];
int tol;
void addedge(int u,int v,int w)
{
edge[tol].v=v;
edge[tol].u=u;
edge[tol++].w=w;
}
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
bool cmp2(Edge a,Edge b)
{
return a.w>b.w;
}
int fnd(int x)
{
return x==F[x]?x:F[x]=fnd(F[x]);
}
int kruskal(int n)
{
for(int i=1;i<=n;i++) F[i]=i;
// sort(edge,edge+tol,cmp);
int cnt=0;
int ans=0;
for(int i=0;i<tol;i++)
{
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].w;
int a=fnd(u);
int b=fnd(v);
if(a!=b)
{
ans+=w;
F[b]=a;
cnt++;
}
if(cnt==n-1)break;
}
if(cnt<n-1)return -1;
return ans;
}
int num[100],cnt;
void init()
{
num[0]=0;num[1]=1;num[2]=2;num[3]=3;
cnt=4;
while(num[cnt-1]<=100005)
{
num[cnt]=num[cnt-1]+num[cnt-2];
cnt++;
// cout<<num[cnt-1]<<endl;
}
}
int main()
{
//freopen("cin.txt","r",stdin);
int t,n,m,cas=1;
scanf("%d",&t);
init();
while(t--)
{
scanf("%d%d",&n,&m);
tol=0;
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);///!!!
}
printf("Case #%d: ",cas++);
sort(edge,edge+tol,cmp);
int small=kruskal(n);
bool ff=true;
sort(edge,edge+tol,cmp2);
int big=kruskal(n);
// printf("s=%d,b=%d\n",small,big);
if(small==-1||big==-1)
{
puts("No");
continue;
}
bool flag=false;
for(int i=1;i<=23;i++)
{
if(num[i]>=small&&num[i]<=big)
{
flag=true;
break;
}
}
if(flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}
22、2015多校第一场(盗墓笔记)
hdu5294Tricks Device【最短路+网络流】
从1开始到n结束,给出双向道路,问至少去掉多少边最短路不是原始最短路长度,至多去掉多少条边最短路长度不变分别利用1与n作为源点 ,分别跑一遍最短路,这个时候两个dist数组记录的就是以1、n为源点的单源最短路长度,理论上他俩无缝接起来都是最短路的方案(理论上是,实际上也是:P )那么我就依次验证给定的边长是否在最短路上,在的话,给这对点建网络流的边(这个题最最讨厌的地方在于函数名,数组名都差不多,特别容易写错)流量是题中给定的第三个数组,求完最短路还要给这对点再建一遍最短路的边,边长为一,这样跑下来dist[n]就是最短路的最短长度了
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<vector>
- #include<queue>
- using namespace std;
- const int inf=0x3f3f;
- const int maxn=2111;
- int n,m;
- struct Edge
- {
- int v,cost;
- Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
- };
- vector<Edge>E[maxn];
- void addedge(int u,int v,int w)
- {
- E[u].push_back(Edge(v,w));
- }
- bool vis[maxn];
- int cnt[maxn];
- int dist[maxn],dist1[maxn];
- bool spfa(int start,int n)
- {
- memset(vis,false,sizeof(vis));
- memset(dist,inf,sizeof(dist));
- vis[start]=true;
- dist[start]=0;
- queue<int>que;
- while(!que.empty()) que.pop();
- que.push(start);
- memset(cnt,0,sizeof(cnt));
- cnt[start]=1;
- while(!que.empty())
- {
- int u=que.front();
- que.pop();
- vis[u]=false;
- for(int i=0;i<E[u].size();i++)
- {
- int v=E[u][i].v;
- if(dist[v]>dist[u]+E[u][i].cost)
- {
- dist[v]=dist[u]+E[u][i].cost;
- if(!vis[v])
- {
- vis[v]=true;
- que.push(v);
- if(++cnt[v]>n) return false;
- }
- }
- }
- }
- return true;
- }
- int w[60009],u[60009],v[60009];
- const int mm=161111;
- const int mn=600009;
- const int oo=1000000000;
- int node,src,dest,edge;
- int reach[mm],flow[mm],nxt[mm];
- int head[mn],work[mn],dis[mn],q[mn];
- inline int min(int a,int b)
- {
- return a<b?a:b;
- }
- inline void prepare(int _node,int _src,int _dest)
- {
- node=_node,src=_src,dest=_dest;
- for(int i=0;i<node;++i)head[i]=-1;
- edge=0;
- }
- inline void addedge(int u,int v,int c1,int c2)
- {
- reach[edge]=v,flow[edge]=c1,nxt[edge]=head[u],head[u]=edge++;
- reach[edge]=u,flow[edge]=c2,nxt[edge]=head[v],head[v]=edge++;
- }
- bool Dinic_bfs()
- {
- int i,u,v,l,r=0;
- for(i=0;i<node;++i)dis[i]=-1;
- dis[q[r++]=src]=0;
- for(l=0;l<r;++l)
- for(i=head[u=q[l]];i>=0;i=nxt[i])
- if(flow[i]&&dis[v=reach[i]]<0)
- {
- dis[q[r++]=v]=dis[u]+1;
- if(v==dest)return 1;
- }
- return 0;
- }
- int Dinic_dfs(int u,int exp)
- {
- if(u==dest)return exp;
- for(int &i=work[u],v,tmp;i>=0;i=nxt[i])
- if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
- {
- flow[i]-=tmp;
- flow[i^1]+=tmp;
- return tmp;
- }dis[u]--;
- return 0;
- }
- int Dinic_flow()
- {
- int i,ret=0,delta;
- while(Dinic_bfs())
- {
- for(i=0;i<node;++i)work[i]=head[i];
- while(delta=Dinic_dfs(src,oo))ret+=delta;
- }
- return ret;
- }
- int bb[mn][2],dist2[mn];
- int main()
- {
- // freopen("cin.txt","r",stdin);
- while(~scanf("%d%d",&n,&m))
- {
- for(int i=0;i<=n;i++) E[i].clear();
- for(int i=0;i<m;i++)
- {
- scanf("%d%d%d",&u[i],&v[i],&w[i]);
- addedge(u[i],v[i],w[i]);
- addedge(v[i],u[i],w[i]);
- }
- spfa(1,n);
- memcpy(dist2,dist,sizeof(dist));
- spfa(n,n);
- int k=0;
- for(int i=0;i<m;i++)
- {
- if(dist2[u[i]]>dist2[v[i]])swap(u[i],v[i]);
- if(dist[v[i]]+w[i]+dist2[u[i]]==dist2[n])
- {
- bb[k][0]=u[i];
- bb[k++][1]=v[i];
- }
- }
- prepare(n+1,1,n);
- for(int i=0;i<k;i++)
- {
- addedge(bb[i][0],bb[i][1],1,0);
- // addedge(bb[i][1],bb[i][0],1);
- }
- int x=Dinic_flow();
- for(int i=0;i<=n;i++) E[i].clear();
- for(int i=0;i<k;i++)
- {
- addedge(bb[i][0],bb[i][1],1);
- addedge(bb[i][1],bb[i][0],1);
- }
- spfa(1,n);
- printf("%d %d\n",x,m-dist[n]);
- }
- return 0;
- }
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int inf=0x3f3f;
const int maxn=2111;
int n,m;
struct Edge
{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
void addedge(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool vis[maxn];
int cnt[maxn];
int dist[maxn],dist1[maxn];
bool spfa(int start,int n)
{
memset(vis,false,sizeof(vis));
memset(dist,inf,sizeof(dist));
vis[start]=true;
dist[start]=0;
queue<int>que;
while(!que.empty()) que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]>dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
int w[60009],u[60009],v[60009];
const int mm=161111;
const int mn=600009;
const int oo=1000000000;
int node,src,dest,edge;
int reach[mm],flow[mm],nxt[mm];
int head[mn],work[mn],dis[mn],q[mn];
inline int min(int a,int b)
{
return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
node=_node,src=_src,dest=_dest;
for(int i=0;i<node;++i)head[i]=-1;
edge=0;
}
inline void addedge(int u,int v,int c1,int c2)
{
reach[edge]=v,flow[edge]=c1,nxt[edge]=head[u],head[u]=edge++;
reach[edge]=u,flow[edge]=c2,nxt[edge]=head[v],head[v]=edge++;
}
bool Dinic_bfs()
{
int i,u,v,l,r=0;
for(i=0;i<node;++i)dis[i]=-1;
dis[q[r++]=src]=0;
for(l=0;l<r;++l)
for(i=head[u=q[l]];i>=0;i=nxt[i])
if(flow[i]&&dis[v=reach[i]]<0)
{
dis[q[r++]=v]=dis[u]+1;
if(v==dest)return 1;
}
return 0;
}
int Dinic_dfs(int u,int exp)
{
if(u==dest)return exp;
for(int &i=work[u],v,tmp;i>=0;i=nxt[i])
if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
{
flow[i]-=tmp;
flow[i^1]+=tmp;
return tmp;
}dis[u]--;
return 0;
}
int Dinic_flow()
{
int i,ret=0,delta;
while(Dinic_bfs())
{
for(i=0;i<node;++i)work[i]=head[i];
while(delta=Dinic_dfs(src,oo))ret+=delta;
}
return ret;
}
int bb[mn][2],dist2[mn];
int main()
{
// freopen("cin.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<=n;i++) E[i].clear();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
addedge(u[i],v[i],w[i]);
addedge(v[i],u[i],w[i]);
}
spfa(1,n);
memcpy(dist2,dist,sizeof(dist));
spfa(n,n);
int k=0;
for(int i=0;i<m;i++)
{
if(dist2[u[i]]>dist2[v[i]])swap(u[i],v[i]);
if(dist[v[i]]+w[i]+dist2[u[i]]==dist2[n])
{
bb[k][0]=u[i];
bb[k++][1]=v[i];
}
}
prepare(n+1,1,n);
for(int i=0;i<k;i++)
{
addedge(bb[i][0],bb[i][1],1,0);
// addedge(bb[i][1],bb[i][0],1);
}
int x=Dinic_flow();
for(int i=0;i<=n;i++) E[i].clear();
for(int i=0;i<k;i++)
{
addedge(bb[i][0],bb[i][1],1);
addedge(bb[i][1],bb[i][0],1);
}
spfa(1,n);
printf("%d %d\n",x,m-dist[n]);
}
return 0;
}
23、次小生成树(秦始皇)
说题意:秦始皇统一中国之后要在全国修公路连接各个城市,抠门皇帝只想修成最小生成树(距离最小,不考虑人力),一个道士说自己可以不花人力物力修一条路,经过两方妥协,选择max(两个城市人口/生成树长度-这条路的长度)的路让他变,求这个比值最大值。
这个题没问次小生成树的值,但是用到了路径最长边这个数组,我叫他Max[][],题中问的是(两个城市人口/生成树长度-这条路的长度),我们首先考虑分母最小,因为对于某个边来说分子是定值啊,分母分成两种情况:1.这个边是最小生成树上的,那啥也别说,mst-cost[][]即可 2.这条边不在最小生成树上:那就是含有这个边的某个生成树,(这么说来这个题应该归纳到次小生成树啊==),mst-Max+cost即可
- #include <iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- using namespace std;
- const int maxn=1010;
- const int inf=0x3f3f3f3f;
- bool vis[maxn],used[maxn][maxn];
- double lowc[maxn];
- int pre[maxn];
- double Max[maxn][maxn],cost[maxn][maxn];
- struct node
- {
- int x,y,pop;
- }num[1010];
- double min(double a,double b){if(a<b) return a;return b;}
- double max(double a,double b){if(a>b) return a;return b;}
- inline double Dist(node v1,node v2)
- {
- return sqrt(double(v1.x-v2.x)*(v1.x-v2.x)+double(v1.y-v2.y)*(v1.y-v2.y));
- }
- double prim(int n)
- {
- double ans=0;
- memset(vis,false,sizeof(vis));
- memset(Max,0,sizeof(Max));
- memset(used,false,sizeof(used));
- vis[0]=true;
- pre[0]=-1;
- for(int i=0;i<n;i++)
- {
- lowc[i]=cost[0][i];
- pre[i]=0;
- }
- // lowc[0]=0.0;
- for(int i=1;i<n;i++)
- {
- double minc=1.0*inf;
- int p=-1;
- for(int j=0;j<n;j++)
- if(!vis[j]&&(minc>lowc[j]||p==-1))
- {
- minc=lowc[j];
- p=j;
- }
- ans+=minc;
- vis[p]=true;
- used[p][pre[p]]=used[pre[p]][p]=true;
- for(int j=0;j<n;j++)
- {
- if(vis[j]&&j!=p)//j!=p必须加!!1
- Max[j][p]=Max[p][j]=max(Max[j][pre[p]],lowc[p]);
- if(!vis[j]&&lowc[j]>cost[p][j])
- {
- lowc[j]=cost[p][j];
- pre[j]=p;
- }
- }
- }
- return ans;
- }
- int main()
- {
- //freopen("cin.txt","r",stdin);
- int t,n;
- scanf("%d",&t);
- while(t--)
- {
- scanf("%d",&n);
- for(int i=0;i<n;i++) scanf("%d%d%d",&num[i].x,&num[i].y,&num[i].pop);
- for(int i=0;i<n;i++)
- for(int j=i+1;j<n;j++)
- cost[i][j]=cost[j][i]=Dist(num[i],num[j]);
- double mst=prim(n);
- // double mst=smst(n,ans);
- double ans=-1;
- for(int i=0;i<n;i++)
- for(int j=i+1;j<n;j++)
- {
- if(used[i][j])//on mst
- ans=max(ans,1.0*(num[i].pop+num[j].pop)/(mst-cost[i][j]));
- else
- ans=max(ans,1.0*(num[i].pop+num[j].pop)/(mst-Max[i][j]));
- }
- printf("%.2f\n",ans);
- }
- return 0;
- }