关于最近的感想以及贴些图论模板

春节后的集训不久前又开始辣~十天的寒假过得跟做梦一样,文化课的的作业匆匆赶完,在我们的认知中“选做=不做”。年前是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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值