DFS与BFS

  • 注意剪枝,边界表示。

  • 状态需要判重时,能不用map尽量不用,能用数字尽量不用字符串

树与图的遍历

  • 正常遍历

  • 拓扑排序:根据入度删点,入度为0的点加入队列bfs

最短路

  • floyd & spfa & dijkstra

spfa:队头出队,松弛它的边,松弛了且不在队内的点入队。

  • 判断负环: 判入队次数是否>n
  • 差分约束:按照dis[v]<=dis[u]+wdis[v] <= dis[u] + w的形式建边求最短路或反之求最长路即可
  • 差分约束最优解 最大值求最短路 最小值求最长路

dij:每次取出当前距离最小的点,表示该点的最短路已经确定。

  • 反向建边

  • 虚点建边

最小生成树

  • prim

  • kruskal

  • 次小生成树?

prim维护f[i][j] 表示最小生成树中 i到j 的最长边

kruscal + lca O(1)离线查询 i到j 的最长边

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define space putchar(' ')
#define endl putchar('\n')
#define debug puts("------------------------")
#define lowbit(x) (x&-x)
#define LOCAL
using namespace std;
inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
inline int  Rem() {int a=0,c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*=b; }
inline void write(int x) {if(x>9)write(x/10);putchar('0'+x%10);}
inline void W(int x) {if(x<0){putchar('-'),x=-x;}write(x);}
/**/
const int inf = 0x3f3f3f3f;
const int N = 105;
int t,n,m,e[N][N],cnt,dis[N],s1,s2,pre[N],f[N][N];
bool tree[N][N], vis[N];
struct edge
{
	int from,to,w;
}ed[N*N];
/**/
int main()
{
	#if ONLINE_JUDGE
	#else
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	#endif
	read(t);
	while(t--)
	{
		cnt = 0;
		read(n);read(m);
		for(int i=1;i<=n;i++)
		{
			pre[i] = 0;
			for(int j=1;j<=i+1;j++) e[i][j] = e[j][i] = inf, tree[i][j] = tree[j][i] = 0, f[i][j] = f[j][i] = 0;
		}
		for(int i=1,a,b,c;i<=m;i++)
		{
			read(a);read(b);read(c);
			ed[++cnt] = (edge){a,b,c};
			e[a][b] = e[b][a] = c;
		}
		for(int i=0;i<=n;i++) dis[i] = inf, vis[i] = 0;
		dis[1] = 0;
		s1 = 0;
		for(int i=1;i<=n;i++)
		{
			int u = 0;
			for(int j=1;j<=n;j++) if(!vis[j]&&dis[j]<dis[u]) u = j;
			vis[u] = 1;
			tree[pre[u]][u] = tree[u][pre[u]] = 1;
			if(u) s1 += dis[u];
			for(int j=1;j<=n;j++)
			{
				if(u==j) continue;
				if(vis[j])
				{
					f[j][u] = f[u][j] = max(f[pre[u]][j], dis[u]);
				}
				if(!vis[j] && dis[j] > e[u][j])
				{
					dis[j] = e[u][j];
					pre[j] = u;
				}
			}
		}
		s2 = inf;
		for(int i=1;i<=cnt;i++)
		{
			int u = ed[i].from, v = ed[i].to;
			if(tree[u][v]) continue;
			// printf("%d - %d = %d\n",u,v,f[u][v]);
			s2 = min(s2, s1 - f[u][v] + ed[i].w);
		}
		cout << s1 <<' '<< s2 <<'\n';
	}
	return 0;
}

  • 有向图有根最小生成树? -> 朱刘算法
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define space putchar(' ')
#define endl putchar('\n')
#define debug puts("------------------------")
#define lowbit(x) (x&-x)
#define LOCAL
using namespace std;
inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
inline int  Rem() {int a=0,c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*=b; }
inline void write(int x) {if(x>9)write(x/10);putchar('0'+x%10);}
inline void W(int x) {if(x<0){putchar('-'),x=-x;}write(x);}
/**/
const int N = 105, M = 1e4 + 5;
int n, cnt, m, fa[N], id[N], vis[N];
double x[N], y[N], in[N];
struct edge
{
   int from, to;
   double w;
}e[M];
/**/
inline double get(int i, int j)
{
   return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
inline double zhuliu()
{
   double ans = 0;
   int root = 1;
   while(1)
   {
   	for(int i = 1; i <= n; i++) in[i] = 0x3f3f3f3f;
   	for(int i = 1; i <= cnt; i++)
   	{
   		int u = e[i].from, v = e[i].to;
   		if(u != v && e[i].w < in[v])
   		{
   			fa[v] = u;
   			in[v] = e[i].w;
   		}
   	}
   	for(int i = 1; i <= n; i++) if(in[i] == 0x3f3f3f3f) return -1;
   	int tot = 0;
   	in[root] = 0;
   	for(int i = 1; i <= n; i++) vis[i] = id[i] = 0;
   	for(int i = 1; i <= n; i++)
   	{
   		int u = i;
   		ans += in[u];
   		while(vis[u] != i && !id[u] && u != root) vis[u] = i, u = fa[u];
   		if(u != root && !id[u])
   		{
   			id[u] = ++tot;
   			for(int x = fa[u]; x != u; x = fa[x]) id[x] = tot;
   		}
   	}
   	if(!tot) break;
   	for(int i = 1; i <= n; i++) if(!id[i]) id[i] = ++tot;
   	int cnt_ = 0;
   	for(int i = 1; i <= cnt; i++)
   	{
   		int u = e[i].from, v = e[i].to;
   		if(id[u] =! id[v]) e[++cnt_] = (edge){id[u], id[v], e[i].w - in[v]};
   	}
   	cnt = cnt_;
   	n = tot;
   	root = id[root];
   }
   return ans;
}
int main()
{
   #if ONLINE_JUDGE
   #else
   freopen("test.in","r",stdin);
   freopen("test.out","w",stdout);
   #endif
   while(cin >> n >> m)
   {
   	cnt = 0;
   	for(int i = 1; i <= n; i++)
   	{
   		cin >> x[i] >> y[i];
   	}
   	for(int i = 1, a, b; i <= m; i++)
   	{
   		read(a); read(b); e[++cnt] = (edge){a, b, get(a, b)};
   	}
   	double ans = zhuliu();
   	if(ans == -1) puts("poor snoopy");
   	else printf("%.2f\n", ans);
   }
   return 0;
}

二分图:

  • 待补习