春节后的集训不久前又开始辣~十天的寒假过得跟做梦一样,文化课的的作业匆匆赶完,在我们的认知中“选做=不做”。年前是DP,什么线性DP、树上DP、斜率优化,(巴拉巴拉)。原本就基础不扎实的我毅然决然逃到A班上搜索(呵呵)快乐的像只猪…(猪年快乐!!!)
这几天来,听得懵懵懂懂,看u盘就知道都学了些啥
2.10:那么多题里只做了一题 [USACO cow contest] 貌似是floyed模板 /xk
2.11:那么多题里只做了两题,尝试做D题结果未尝我愿,一声“哇(WA)” [bzoj3033 太鼓达人、UVa 10129 - Play on Words] 一题是欧拉回路,另一题是有向图欧拉回路。
2.12:那么多题里只做了三题 [Power Plant、poj 2349 Arctic Network、安慰奶牛] 分别涉及缩点、等价转换、边权处理
2.13:那么多题里只做了三题 [树的直径模板题,Two(树的直径),树的重心模板题] 离不开模板
今天早上讲树的直径、重心和基环树,根本没听,唯一的收获是知道了这些专有名词/xk。上课就像是听天书,从在线上机到离线挂机、卡机、关机,再加上超级困,就这样白白浪费时间坐了一早上。这时候就会体会到有句话说的很好:“人最烦躁的时候就是:当能力不足而无事可做的时候,想做些什么但又什么也不可做。”(虽然这句话是我自己说的)
上午坐在录播教室里,下午坐在机房里,晚上依旧在机房老窝。一整天除了去吃饭,睡觉,上厕所的时候都是坐着的(为什么要加"去"呢?因为在过程中不是坐着就是蹲着,不是蹲着就是躺着,跟坐着没差/kb)总感觉要比别人老得快呢/xk,现在我的眼睛像是被抹了一层辣椒…
在这次集训中,想家是不可避免的,虽说我不是那种轻易动思家之情的人,但是假期时间比以往缺好多啊,家又离这里远,班里大部分人都是当地的,随时一个电话,一个要求,立马可以走人,看着他们,心情不免有些失落(苦笑),我也是不争气的,那些积起来的坏脾气,虽隔得那么远,还是在QQ上炮语连珠地向老妈发泄。
说实话,虽然我知道要做好当下,但是我真的不是很喜欢这个东西。我始终搞不懂舍弃那么多时间来搞这个是为了什么,竞争那么残酷,自己无疑是这战争中的牺牲品,时间对于现在的我来说是很宝贵的,老师却依旧让我们坚持,内心不免十分犹豫,而我始终搞不懂这是为什么,又有些什么意义,这反而耽误了对于我来说的其他方面,舍弃的不仅仅是时间,还有很多很多,我舍弃了自己的想尝试兴趣的一点心思、舍弃了和亲人待在一起的时光,我还舍弃了对未来的一份坚定…不过时间久了,未来我应该可以弄明白
希望我之后能寻到当下…
在说闲话中间我想先穿插一些进来的模板:
最短路:
floyed:
void floyed()
{
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];
}
dijkstra:
作者 博客园yoyo_sincerely
链接
const int INF=0x3f3f3f3f;
const int maxn=1200;
int dist[maxn],g[maxn][maxn],N;
bool vis[maxn];
void dijkstra()
{
for(int i=1;i<=N;i++)
dist[i]=(i==1)?0:INF;
memset(vis,0,sizeof(vis));
for(int i=1;i<=N;i++)
{
int mark=-1,mindis=INF;
for(int j=1;j<=N;j++)
{
if(!vis[j]&&dist[j]<mindis)
{
mindis=dist[j];
mark=j;
}
}
vis[mark]=1;
for(int j=1;j<=N;j++)
{
if(!vis[j])
{
dist[j]=min(dist[j],dist[mark]+g[mark][j]);
}
}
}
}
dijkstra+heap(堆优化):
作者 博客园yoyo_sincerely
链接
// 堆优化dijkstra
void dijkstra()
{
memset(dist,63,sizeof(dist));
dist[S]=0;
priority_queue<pII> q; /// -距离,点
q.push(make_pair(0,S));
while(!q.empty())
{
pII tp=q.top(); q.pop();
int u=tp.second;
if(vis[u]==true) continue;
vis[u]=true;
for(int i=Adj[u];i;i=edge[i].next)
{
int v=edge[i].to;
int len=edge[i].len;
if(vis[v]) continue;
if(dist[v]>dist[u]+len)
{
dist[v]=dist[u]+len;
q.push(make_pair(-dist[v],v));
}
}
}
}
SPFA:
作者 Faithfully__xly
链接
#include<bits/stdc++.h>
#define N 10009
#define M 500009
using namespace std;
int dis[N],nxt[M],to[M],w[M],head[N];
int n,m,s;
queue<int> q;
int tot=0;
bool vis[N];
void add(int x,int y,int z){
nxt[++tot]=head[x];
head[x]=tot;
w[tot]=z;
to[tot]=y;
}
void spfa(int u){
q.push(u);
vis[u]=1;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(dis[x]+w[i]<dis[y]){
dis[y]=dis[x]+w[i];
if(!vis[y]) vis[y]=1,q.push(y);
}
}
}
}
int main(){
cin>>n>>m>>s;
int i,j,k;
for(i=1;i<=m;++i)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
//add(read(),read(),read());不能直接写
}
for(i=1;i<=n;++i)
{
dis[i]=2147483647;//这是模板题要求的大小,一般情况下设为极大值即可
vis[i]=0;
}
dis[s]=0;
spfa(s);
for(i=1;i<=n;++i)
printf("%d ",dis[i]);
return 0;
}
图论其他算法:
欧拉回路:
作者 almz654321
链接
#include <bits/stdc++.h>
using namespace std;
int n,m,pic[1100][1100],d[1100],road[1500],now;
void dfs(int x)
{
for(int i=1;i<=500;i++)
if(pic[x][i])
{
pic[x][i]--; //注意可能有重边
pic[i][x]--;
dfs(i);
}
road[++now]=x; //记录路径
}
int main()
{
cin>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
pic[x][y]++;
pic[y][x]++;
d[x]++;
d[y]++;
}
int st=1; //如果无度为1的点,则从任意点开始搜,即寻找欧拉回路
for(int i=1;i<=500;i++) //如果有度为1的点,则从该点开始搜,即寻找欧拉路
if(d[i]%2)
{
st=i;
break;
}
dfs(st);
for(int i=now;i>=1;i--)
{
cout<<road[i]<<endl;
}
return 0;
}
有向图欧拉回路:
作者 fengsigaoju
链接
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
int n;
int a[101][101];
int indegree[101];
int outdegree[101];
int bfs();
int ans[101][101];
int compare();
void print(int i);
int main()
{
int m,i,j,c,d;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
scanf("%d%d",&c,&d);
a[c][d]=1;
outdegree[c]++;//c的出度加一
indegree[d]++;//d的入度加一
}
if (!bfs())//如果图本身不连通
printf("No\n");
else
if (compare())//如果入度等于出度
{
printf("Yes\n");
printf("路径为:\n");
print(1);
}
else
printf("No\n");
return 0;
}
int bfs()
{
queue<int>q;
int i;
int vis[101],temp;//标记是否访问过
for (i=1;i<=n;i++)
vis[i]=0;
q.push(1);
vis[1]=1;
while(!q.empty())
{
temp=q.front();
q.pop();
for (i=1;i<=n;i++)
if ((a[temp][i])&&(!vis[i]))
{
vis[i]=1;
q.push(i);
}
}
for (i=1;i<=n;i++)
if (!vis[i])
{
printf("%d\n",i);
return 0;
}
return 1;
}
int compare()
{
int i;
for (i=1;i<=n;i++)
if (indegree[i]!=outdegree[i])
return 0;
return 1;
}
void print(int i)
{
int v;
for (v=1;v<=n;v++)
if ((a[i][v])&&(!ans[i][v]))
{
ans[i][v]=1;
printf("%d->%d\n",i,v);
print(v); //递归搜索路径
}
}
拓扑排序:
作者 博客园 非我非非我
链接
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int indegree[100];
int n,m;
bool map[100][100];
int a[100];
int topu()
{
queue<int> q;
int cnt = 1;
while(!q.empty())//清空队列
q.pop();
for(int i = 1; i <= n ; i++)
if(indegree[i] == 0)
q.push(i);//将 没有依赖顶点的节点入队
int u;
while(!q.empty()) //
{
u = q.front();
a[cnt++] = u;//将上边选出的没有依赖顶点的节点加入到排序结果中
q.pop();//删除队顶元素
for(int i = 1; i <= n ; i++)
{
if(map[u][i])
{
indegree[i] --;//删去以u为顶点的边
if(indegree[i] == 0) //如果节点i的所有依赖顶点连接边都已经删去
q.push(i); //即变为无依赖顶点的节点 将其入队
}
}
if(cnt == n)//如果排序完成输出结果
{
for(int i = 1 ; i <= n ; i++)
printf(" %d",a[i]);
}
}
}
int main()
{
int u,v;
while(~scanf("%d%d",&n,&m))
{
memset(indegree,0,sizeof(indegree));
memset(map,0,sizeof(map));
for(int i = 0 ; i < m ; i++)
{
scanf("%d%d",&u,&v);
if(!map[u][v])//考虑重边
{
indegree[v]++;//连接v的边的条数
map[u][v] = 1;//标记u v已经连接
}
}
topu();
}
return 0;
}
差分约束:
作者 博客园 JsonFive
链接
#include <cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
#define N 50005
#define M 500009
const int inf=0x3f3f3f3f;
int dis[N],head[N];
queue<int> q;
int tot;
bool vis[N];
struct Edge
{
int from,to,cost,next;
} edge[M];
void add(int u,int v,int w)
{
edge[tot].from=u;
edge[tot].to=v;
edge[tot].cost=w;
edge[tot].next=head[u];
head[u]=tot++;
}
void spfa(int u)
{
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[u]=0;
q.push(u);
vis[u]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x]; ~i; i=edge[i].next)
{
int y=edge[i].to;
if(dis[x]+edge[i].cost<dis[y])
{
dis[y]=dis[x]+edge[i].cost;
if(!vis[y]) vis[y]=1,q.push(y);
}
}
}
}
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
init();
int a,b,w;
int mina=1e9,maxb=-mina;
for (int i=0; i<n ; i++ )
{
scanf("%d%d%d",&a,&b,&w);
a++;
b++;
add(b,a-1,-w);
mina=min(mina,a);
maxb=max(maxb,b);
}
for (int i=mina-1; i<maxb ; i++ )
{
add(i+1,i,0);
add(i,i+1,1);
}
int s=maxb;
int t=mina-1;
spfa(s);
printf("%d",-dis[t]);
}
return 0;
}
最小生成树:
Kruskal(克鲁斯卡尔):
作者 McDonnell_Douglas
链接
//克鲁斯卡尔算法求最小生成树
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<string>
#include<cstring>
#include<ctime>
using namespace std;
struct bian
{
int x; //边的起点
int y; //边的终点
int w; //边的长度
};
bian a[20000]; //a[i]存储第i条边的信息
int father[201]; //father[i]表示第i个点的根
int n,i,j,x,m,tot,k; //tot存储最小生成树边的总长度(最小的);m是边的数量
bool comp(const bian &a,const bian &b) //自设比较函数
{
return a.w<b.w; //按边的长度从小到大排序
}
int getfather(int x) //找x的根
{
if (father[x]==x) return x;
father[x]=getfather(father[x]);
return father[x];
}
void unionn(int x,int y) //把x、y合并到一个连通块
{
int fa,fb;
fa=getfather(x);
fb=getfather(y);
if (fa!=fb) father[fa]=fb;
}
int main()
{
freopen("agrinet.in","r",stdin);
freopen("agrinet.out","w",stdout);
scanf("%d",&n); //读入点的数量n
m=0;
for(i=1;i<=n;i++) //存储每条边
for(j=1;j<=n;j++)
{
scanf("%d",&x);
if(x!=0)
{
m++; //累加边的数量
a[m].x=i; //存第m条边的起点
a[m].y=j; //存第m条边的终点
a[m].w=x; //存第m条边的长度
}
}
for(i=1;i<=n;i++) father[i]=i; //初始化:每个点单独是一个联通块
sort(a+1,a+m+1,comp); //按边的长度从小到大排序
for(i=1;i<=m-1;i++) //Kruskal算法,依次处理每一条边
{
if(getfather(a[i].x)!=getfather(a[i].y)) //如果第i条边的两个端点不在一个联通块中
{
unionn(a[i].x,a[i].y); //合并第i条边的两个点
tot=tot+a[i].w; //累加最小生成树长度
k++; //计算生成树中边的数量
}
if(k==n-1) break; //如果已经加入了n-1条边,则最小生成树建立完成
}
printf("%d\n",tot);
return 0;
}
Prim:
作者 纯真zwj
链接
<span style="font-size:12px;">#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f
int lowcost[110];//此数组用来记录第j个节点到其余节点最少花费
int map[110][110];//用来记录第i个节点到其余n-1个节点的距离
int visit[110];//用来记录最小生成树中的节点
int city;
void prime()
{
int min,i,j,next,mincost=0;
memset(visit,0,sizeof(visit));//给最小生成树数组清零
for(i=1;i<=city;i++)
{
lowcost[i]=map[1][i];//初始化lowcost数组为第1个节点到剩下所有节点的距离
}
visit[1]=1;//选择第一个点为最小生成树的起点
for(i=1;i<city;i++)
{
min=INF;
for(j=1;j<=city;j++)
{
if(!visit[j]&&min>lowcost[j])//如果第j个点不是最小生成树中的点并且其花费小于min
{
min=lowcost[j];
next=j;//记录下此时最小的位置节点
}
}
if(min==INF)
{
printf("?\n");
return ;
}
mincost+=min;//将最小生成树中所有权值相加
visit[next]=1;//next点加入最小生成树
for(j=1;j<=city;j++)
{
if(!visit[j]&&lowcost[j]>map[next][j])//如果第j点不是最小生成树中的点并且此点处权值大于第next点到j点的权值
{
lowcost[j]=map[next][j]; //更新lowcost数组
}
}
}
printf("%d\n",mincost);
}
int main()
{
int road;
int j,i,x,y,c;
while(scanf("%d%d",&road,&city)&&road!=0)
{
memset(map,INF,sizeof(map));//初始化数组map为无穷大
while(road--)
{
scanf("%d%d%d",&x,&y,&c);
map[x][y]=map[y][x]=c;//城市x到y的花费==城市y到想的花费
}
prime();
}
return 0;
}</span>
主要:
作者 心若向阳_无谓悲伤
链接
void Prim(){
int i,j,k,tmp,ans;
for(i=1;i<=n;i++)
dis[i]=inf;//初始化
dis[1]=0;
for(i=1;i<=n;i++){
tmp=inf;
for(j=1;j<=n;j++){
if(!vis[j]&&tmp>dis[j]){
tmp=dis[j];
k=j;
}//找出最小距离的节点
}
vis[k]=1;//把访问的节点做标记
for(j=1;j<=n;j++){
if(!vis[j]&&dis[j]>map[k][j])
dis[j]=map[k][j];//更新最短距离
}
}
}
瓶颈生成树不贴了
关于树:
树的直径:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
using namespace std;
struct edge
{
int nxt,to,vl;
}e[501010];
int last[40010];
int n,m;
int dis[40100],vis[41010];
int cnt=0;
int p,maxx;
void add(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].vl=w;
e[cnt].nxt=last[u];
last[u]=cnt;
}
void bfs(int x)
{
queue<int> q;
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
vis[x]=1;q.push(x);
maxx=0;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=last[now];i;i=e[i].nxt)
{
int t=e[i].to;
if(!vis[t])
{
q.push(t);
vis[t]=1;
dis[t]=dis[now]+e[i].vl;
}
}
}
for(int i=1;i<=n;i++)
if(dis[i]>maxx)
{
maxx=dis[i];
p=i;
}
}
int main()
{
char ch;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
cin>>ch;
add(a,b,c);
add(b,a,c);
}
bfs(1);bfs(p);
cout<<maxx<<endl;
return 0;
}
树的重心:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
using namespace std;
int n;
struct edge
{
int to,nxt;
}e[101010001];
int last[101010];
int son[101011];
int vis[101010];
int cnt,ans,size;
void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].nxt=last[u];
last[u]=cnt;
}
void dfs(int x)
{
vis[x]=1;
son[x]=0;
int sum=0;
for(int i=last[x];i>0;i=e[i].nxt)
{
int t=e[i].to;
if(!vis[t])
{
dfs(t);
son[x]+=son[t]+1;
sum=max(sum,son[t]+1);
}
}
sum=max(sum,n-son[x]-1);
if(sum<size||(sum==size&&x<ans))
{
ans=x;
size=sum;
}
// cout<<ans<<' '<<size<<endl;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cnt=0;
size=101010101;
memset(vis,0,sizeof(vis));
memset(last,-1,sizeof(last));
cin>>n;
for(int i=1;i<n;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
dfs(1);
cout<<ans<<' '<<size<<endl;
}
return 0;
}
基环树:
盗用一下老师的课件,事实上我并不会写
这几天的模板就先贴到这里,现在繁琐之事业已告一段落,接下来正经的扯闲话。
在春节前的集训时的某一天晚上,我在机房,音乐从耳机里传出,轻轻地。我这时也是思绪万千,期末成绩刚出来,虽说考得不错但还是有些不大满意,和爸妈分别已久更是让我禁不住随心写了一篇感想。部分截图在这:
今天老师又给一些人灌了些心灵鸡汤:不要放弃,你们进步很大
对于我来说,不放弃是这个故事的延续,放弃了又是另一个故事,不管是哪个故事,结局我都不确定,这一切都要靠那个握笔的人掌握,而我又是那个握笔的人。那么,造就一个好故事,需要笔者高超的能力,只能用时间不断的磨练,不过,我只希望故事的转变不要来得太早,也不要来的太晚,省的留下无法抹去的遗憾。希望人人都能找到当下和未来的归属吧。
此致。
2019.2.13