8.12
待完成:
- P1265 公路修建
- P1983 车站分级
- P1439 【模板】最长公共子序列
- P1807 最长路_NOI导刊2010提高(07)
任务:
最小生成树较复杂图论I
模板归纳
kruskal:
注意在存矩阵的图的时候边数要开n*n,如下图
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
rep(i,1,n)
rep(j,1,n){
int x;rd(x);
if(j>i)
e[++tot].u=i,e[tot].v=j,e[tot].w=x;
}
void kruskal(){
rep(i,1,边数){
int fx=find(e[i].u),fy=find(e[i].v);
if(fx==fy)continue;
fa[fx]=fy;
ans+=e[i].w;
或ans=min/max(ans,e[i].w);
if(++tot==n-1)break;
}
}
sort(e+1,e+边数+1);
rep(i,1,点数)fa[i]=i;
kruskal();
P1144 【模板】最短路计数
/*
reference:
translation:
solution:
- 如果这个点的最短路可以更新但还未被更新即 if(dis[v]>dis[u]+1),
可到达这个点的最短路就是通过先到达上个点再走当前边的方式,ans[v]=ans[u];
- 当一个点不能被当前点更新时,判断如果这个点的距离等于当前点距离+1的话,
那么就同上,可到达这个点的最短路有一种是通过先到达上个点再走当前边的方式得到的,那么我们就把这个情况加上,可得代码
ans[v]+=ans[u]
trigger:
note:
*用spfa进行最短路计数
*初始化:ans[1]=1;
date:
2019.08.12
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=(a);i<=(b);++i)
#define dwn(i,a,b) for(ll i=(a);i>=(b);--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)
#define M 2000000
#define N 1000000
#define mod 100003
struct e{
int v,next,w;
}e[M<<1];
int cnt,n,m;
int head[N],dis[N],ans[N];
bool vis[N];
void add(int u,int v,int w){e[++cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;}
void spfa(int s){
queue<int>q;
mem(dis,0x3f);
mem(vis,0);
q.push(s);
vis[s]=1;
dis[s]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
ee(i,u){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+1){
dis[v]=dis[u]+1;
ans[v]=ans[u]%mod;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
else if(dis[v]==dis[u]+1){
(ans[v]+=ans[u])%=mod;
}
}
}
}
int main(){
ans[1]=1;//
rd(n),rd(m);
while(m--){
int u,v,w;rd(u),rd(v);
add(u,v,1),add(v,u,1);
}
spfa(1);
rep(i,1,n)printf("%d\n",(ans[i]+mod)%mod);
return 0;
}
刷题表
P1007 独木桥
奇技淫巧:当两个士兵撞在一起时,从上帝视角看会发生什么?当然他们认为他们都掉头了,但因为你在特高的地方,你会认为他们“穿过”了对方。换言之,这与他们相互穿过并没有任何区别。
P1629 邮递员送信
建反向图,将返回总部的多源最短路变成单源最短路
P1462 通往奥格瑞玛的道路
spfa+二分
P1119 灾后重建
floyd的本质
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=(a);i<=(b);++i)
#define dwn(i,a,b) for(ll i=(a);i>=(b);--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)
#define N 210
const int inf=0x3f3f3f3f;
int n,m,q;
int t[N],dis[N][N];
int main(){
freopen("zaiqu.txt","r",stdin);
mem(dis,0x3f3f3f3f);
rep(i,1,n)dis[i][i]=0;//////////////////////////
rd(n),rd(m);
rep(i,1,n)rd(t[i]);
rep(i,1,m){
int u,v,w;rd(u),rd(v),rd(w);
dis[u+1][v+1]=dis[v+1][u+1]=w;
}
rd(q);
while(q--){
int u,v,limit,k=1;rd(u),rd(v),rd(limit);
for(;t[k]<=limit && k<=n;++k)
rep(i,1,n)
if(i!=k)
rep(j,1,n)
if(i!=k && k!=j)
dis[i][j]=dis[j][i]=min(dis[i][j],dis[i][k]+dis[k][j]);
if(t[u+1]>limit || t[v+1]>limit)puts("-1");
else {
if(dis[u+1][v+1]<0x3f3f3f3f)
printf("%d\n",dis[u+1][v+1]);
else puts("-1");
}
}
return 0;
}
P1346电车
/*
reference:
https://www.luogu.org/blog/user43601/solution-p1346
translation:
solution:
trigger:
数据规模在200,用Floyd求多源最短路,把默认的路径边权设为0,其他路径设为1,跑一边最短路。
note:
*floyd、巧妙建图
date:
2019.08.12
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)
#define N 210
const int inf=0x3f3f3f3f;
int cnt,n,s,t;
int dis[N][N];
int main(){
#ifdef WIN32
freopen("","r",stdin);
#endif
mem(dis,inf);
rep(i,1,n)dis[i][i]=0;
rd(n),rd(s),rd(t);
rep(i,1,n){
int k,x;rd(k);
rep(j,1,k){
rd(x);
if(j==1)dis[i][x]=0;
else dis[i][x]=1;
}
}
rep(k,1,n)
rep(i,1,n)
if(k!=i)
rep(j,1,n)
if(j!=i && j!=k)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
if(dis[s][t]==inf)puts("-1");
else printf("%d\n",dis[s][t]);
return 0;
}
P1991 无线通讯网
/*
reference:
translation:
solution:
- 做本题首先应该知道一共有p个点就是树有p-1条边,有s个无线电收发器就是不用连接最大的s-1条边。
- 因为数据范围小,本题适用kruskal。存储每条边的权值和两端进行排序。
- 树中前(p-s)条边里的最大边即可,剩下的边用卫星电话。
trigger:
note:
*最小生成树
record:
1st:[independent]60pts;
2nd:[analysis]100 pts
date:
2019.08.12
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)
#define N 250010
struct edge{
int u,v;
double w;
bool operator < (const edge &rhs)const{
return w<rhs.w;
}
}e[N];
int n,s,cnt,tot;
double ans;
int x[N],y[N],fa[N];
double dist(int i,int j){return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void kruskal(){
rep(i,1,cnt){
int fx=find(e[i].u),fy=find(e[i].v);
if(fx==fy)continue;
fa[fx]=fy;
ans=max(ans,e[i].w);
if(++tot==n-s)break;//////////////////////////////////////////
}
}
int main(){
#ifdef WIN32
//freopen("wireless.txt","r",stdin);
#endif
rd(s),rd(n);
rep(i,1,n)rd(x[i]),rd(y[i]);
rep(i,1,n-1)
rep(j,i+1,n){
double w=dist(i,j);
e[++cnt].u=i,e[cnt].v=j,e[cnt].w=w;
}
sort(e+1,e+cnt+1);
rep(i,1,n)fa[i]=i;
kruskal();
printf("%.2lf",ans);
return 0;
}
/*
2 4
0 100
0 300
0 600
150 750
*/
//212.13
P1194 买礼物
/*
reference:
translation:
solution:
trigger:
note:
*最小生成树,类似P1546,
*新建一个“0”号节点,所以(++cnt==n)break;
*注意x==0 的情况
record:
date:
2019.08.12
*/
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
struct edge{
int u,v,w;
bool operator <(const edge &rhs)const{
return w<rhs.w;
}
}e[250010];
int fa[1100],n,tot,ans,a;
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void kruskal(){
int cnt=0;
rep(i,1,tot){
int fx=find(e[i].u),fy=find(e[i].v);
if(fx!=fy){
fa[fx]=fy;
ans+=e[i].w;
if(++cnt==n)break;
}
}
}
int main(){
rd(a),rd(n);
rep(i,1,n)
e[++tot].u=0,e[tot].v=i,e[tot].w=a;
rep(i,1,n)
rep(j,1,n){
int x;rd(x);
if(j>i && x){//如果x为0就按照a算
e[++tot].u=i,e[tot].v=j,e[tot].w=x;
}
}
sort(e+1,e+tot+1);
rep(i,1,n)fa[i]=i;
kruskal();
printf("%d",ans);
return 0;
}
P1113 杂务
/*
reference:
translation:
solution:
trigger:
note:
*topo_sort
record:
date:
2019.08.12
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)
#define N 10005
queue <int> q;
bool e[N][N];
int tim[N],mx[N],deg[N];//mx[i]:第i物体
int n,ans;
void topo(){
rep(i,1,n)
if(deg[i]==0){
q.push(i);
mx[i]=tim[i];
}
while(!q.empty()){
int u=q.front();
q.pop();
rep(i,1,n){
if(e[u][i]){
deg[i]--;
if(deg[i]==0)q.push(i);
mx[i]=max(mx[i],mx[u]+tim[i]);
}
}
}
rep(i,1,n)
ans=max(ans,mx[i]);
}
int main(){
rd(n);
rep(i,1,n){
int id,w,x;
rd(id),rd(w),rd(x);
tim[id]=w;
while(x!=0){
deg[id]++;
e[x][id]=true;
rd(x);
}
}
topo();
printf("%d",ans);
return 0;
}
P1268 树的重量
本质:去重
/*
reference:
https://www.luogu.org/blog/virus2017/p1268
translation:
solution:
trigger:
note:
*
date:
2019.08.12
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;++i)
#define dwn(i,a,b) for(ll i=a;i>=b;--i)
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;}
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,x) for(int i=head[x];i;i=e[i].next)
#define N 35
int n,dis[N][N];
int main(){
while(~scanf("%d",&n) && n){
rep(i,1,n)
rep(j,1,n)
if(j>i)
rd(dis[i][j]);
int ans=dis[1][2];
rep(i,3,n){//从第三个点开始算
int tmp=0x7fffffff;
rep(j,2,i-1)//从之前的点来更新i
tmp=min(tmp,dis[1][i]+dis[j][i]-dis[1][j]>>1);
ans+=tmp;
}
printf("%d\n",ans);
}
return 0;
}