第一天来海亮,这真是个学习(吃喝)、刷题(玩乐)的好地方!!!废话不多说,进行今天的总结。。。
最短路
Floyed
先粘题目(板子题):POJ 3360
直接上代码:
#include<bits/stdc++.h>//谁想打那么长的数据库O^O
using namespace std;
int n,m,ans,xx,yy;
int a[1000][1000],d[1000][1000];
void floyed()
{
for(int k=1;k<=n;k++)//最重要的k循环放在最外面
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=a[i][j]|a[i][k]&a[k][j];
//floyed的核心代码,就好比是三角形两边之和大于第三边
//floyed是个O(n3)的做法,只能解决小数据,在解图论题时是个暴力的万能算法
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=0;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
a[x][y]=1;
}
floyed();
for(int i=1;i<=n;i++)
{
int w=0;
for(int j=1;j<=n;j++)
if(a[i][j]==1||a[j][i]==1)
w++;
if(w==n-1) ans++;
}
cout<<ans;
return 0;
}
Djkstra
dijkstra主要是以起始点为中心向外层层扩展,直到扩展到终点为止,显然这是一个 O(n2)的算法,倘若用堆优化一下,就变成了O(mlogn)的优秀算法。(突然想到当初在机房学dijkstra用了好几天,还是去集训学的效率高)
typedef pair <int,int> pii;
priority_queue <pii,vector<pii>,greater<pii> > Q;
//堆优化的dijkstra
void dijkstra()
{
memset(d,127,sizeof(d));
d[1]=0;
Q.push(mp(0,1));//mp就是pair( , )
while(Q.size())
{
int x=Q.top().second; Q.pop();
if(v[x]) continue;
v[x]=true;
for(int i=last[x];i;i=e[i].next)
//最基本的邻接表边的遍历
{
int y=e[i].too,z=e[i].z;
if(d[y]>d[x]+z)
{
d[y]=d[x]+z;
Q.push(mp(-d[y],y));
}
}
}
}
放个板子题:HYSBZ - 4152
#include<bits/stdc++.h>//谁想打那么长的数据库O^O
using namespace std;
bool v[210000];
int n,tot,d[210000];
struct see {int x,y,c,next,last;}a[810000];
void add(int x,int y,int c)
{
a[++tot].x=x;a[tot].y=y;a[tot].c=c;
a[tot].next=a[x].last;a[x].last=tot;
}
struct zuobiao {int x,y,qq;}g[210000];
bool cmg1(see a,see b){return a.x<b.x;}
bool cmg2(see a,see b){return a.y<b.y;}
struct gg
{
int x;
friend bool operator <(gg n1,gg n2)
{return d[n1.x]>d[n2.x];}
};
priority_queue<gg> Q;
void dijkstra()
{
memset(d,100,sizeof(d));
memset(v,false,sizeof(v));
d[1]=0;
v[1]=true;
gg tmp;
tmp.x=1;Q.push(tmp);
while(!Q.empty())
{
tmp=Q.top();int x=tmp.x;
for(int k=a[x].last;k;k=a[k].next)
{
int y=a[k].y;
if(d[y]>d[x]+a[k].c)
{
d[y]=d[x]+a[k].c;
if(v[y]==false)
{
v[y]=true; gg ss;
ss.x=y; Q.push(ss);
}
}
}
Q.pop(); v[x]=false;
}
}//就是一个dijkstra+堆优化的板子题
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&g[i].x,&g[i].y),g[i].qq=i;
sort(g+1,g+1+n,cmg1);
for(int i=1;i<=n;i++)
add(g[i].qq,g[i+1].qq,g[i+1].x-g[i].x),
add(g[i+1].qq,g[i].qq,g[i+1].x-g[i].x);
sort(g+1,g+1+n,cmg2);
for(int i=1;i<=n;i++)
add(g[i].qq,g[i+1].qq,g[i+1].y-g[i].y),
add(g[i+1].qq,g[i].qq,g[i+1].y-g[i].y);
//由于题目上只给了坐标,所以要分x,y排序(很恶心的排序,并不想写它)
dijkstra();
printf("%d\n",d[n]);
return 0;
}
SPFA
一个在中国非常流行的最短路算法,·很好的解决了dijkstra无法判断负环的算法(还有Bell-ford,但我不是很清楚,只是听说SPFA是它的队列优化,就直接学了spfa。。。)
void spfa()
{
queue<int>Q;
Q.push(0);//从0开始跑最短路,并把0放入队列
v[0]=true;//访问数组
d[0]=0; //记录最短路路程
while(!Q.empty())
{
int x=Q.front(); Q.pop(); v[x]=false;
for(int i=last[x];i;i=e[i].next)
{
int y=e[x].ver,z=e[i].edge;
if(d[y]>d[x]+z)
{
d[y]=d[x]+z;
if(!v[y])
v[y]=true,Q.push(y);
}
}
}
}
放一个SPFA和基础数论结合的题:
HYSBZ - 2118
很有意思的一个最短路题。。。(不想吐槽)
题解:(之后再补充>_<,请相信我!!!)
#include<bits/stdc++.h>//谁想打那么长的数据库O^O
#define sea 500010
#define ll long long
using namespace std;
bool v[sea]={0};
int a[20],n,mm=(1<<30)-1;
ll l,r,d[sea];//瞟一眼数据就必须要开ll
void spfa()
{
queue<int>Q;
Q.push(0);
v[0]=true;
d[0]=0;
int x,y;
while(!Q.empty())
{
x=Q.front(); Q.pop(); v[x]=false;
for(int i=1;i<=n;i++)
{
y=(x+a[i])%mm;
if(d[y]>d[x]+a[i])
{
d[y]=d[x]+a[i];
if(!v[y])
v[y]=true,Q.push(y);
}
}
}
}//spfa在这里面就是个板子(它在哪不是板子。。)
ll cf(ll x)//差分
{
ll ans=0;
for(int i=0;i<mm;i++)
if(d[i]<=x) ans+=(x-d[i])/mm+1;
return ans;
}
int main()
{
cin>>n>>l>>r;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]==0)
{
i--,n--;
continue;
}
mm=min(a[i],mm);
}
for(int i=0;i<mm;i++)
d[i]=100000000000000000LL;
spfa();
cout<<cf(r)-cf(l-1);
return 0;
}
然后是一个新颖 的知识:分层图
先上一个题:HYSBZ - 2662
分层图:
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define mp make_pair
using namespace std;
int tot,n,m,k,last[220009],d[220009];
struct see{int z,too,next;}e[4200009];
bool v[220009];
void add(int x,int y,int z){e[++tot].too=y; e[tot].z=z; e[tot].next=last[x]; last[x]=tot;}
typedef pair <int,int> pii;
priority_queue <pii,vector<pii>,greater<pii> > Q;
void dijkstra()
{
memset(d,127,sizeof(d));
d[1]=0;
Q.push(mp(0,1));
while(Q.size())
{
int x=Q.top().second; Q.pop();
if(v[x]) continue;
v[x]=true;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].too,z=e[i].z;
if(d[y]>d[x]+z)
{
d[y]=d[x]+z;
Q.push(mp(d[y],y));
}
}
}
}//也是个dijkstra+堆优化的板子
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
for (int j=1;j<=k;++j)
{
add(j*n+x,j*n+y,z);
add(j*n+y,j*n+x,z);
add((j-1)*n+x,j*n+y,z/2);
add((j-1)*n+y,j*n+x,z/2);
//在原图上又加了一层,具体可以看上图
}
}
dijkstra();
int ans=d[n];
for (int i=0;i<=k;++i)
ans=min(ans,d[i*n+n]);
cout<<ans;
return 0;
}
双倍经验:P4568 [JLOI2011]飞行路线
#include<bits/stdc++.h>
#define sea 1000010
using namespace std;
int n,m,k,s,t,a,b,c,d[sea],last[sea],tot=0;
bool vis[sea];
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
return s*w;
}
struct see{int ver,next,edge;}e[6000060];
void add(int x,int y,int z){e[++tot].ver=y;e[tot].edge=z;e[tot].next=last[x];last[x]=tot;}
void dijkstra(int s)
{
memset(d,0x3f,sizeof(d)); d[s]=0;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > Q;
Q.push(make_pair(0,s));
while(!Q.empty())
{
int x=Q.top().second; Q.pop();
if(!vis[x])
{
vis[x]=1;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].ver;
if(d[y]>d[x]+e[i].edge)
{
d[y]=d[x]+e[i].edge;
Q.push(make_pair(d[y],y));
}
}
}
}
}
int main()
{
n=read(); m=read(); k=read(); s=read(); t=read();
for(int i=1;i<=m;i++)
{
int x,y,z;
x=read(); y=read(); z=read();
add(x,y,z),add(y,x,z);
for (int j=1;j<=k;++j)
{
add((j-1)*n+x,j*n+y,0);
add((j-1)*n+y,j*n+x,0);
add(j*n+x,j*n+y,z);
add(j*n+y,j*n+x,z);
}
}
for(int i=1;i<=k;++i) add(t+(i-1)*n,t+i*n,0);
dijkstra(s);
printf("%d",d[t+k*n]);
return 0;
}
大概好像我学到的就这么点了,老师讲的好像也就这么多吧0.0(冰山效应)。
愉快的结束了第一天,尽管没有写完题,但很开心,学到了很多,,,总结就这样吧。