- 邻接表
struct edge { int to, cost; };//保存信息到达边和权值
vector<edge>g[1000];
int main()
{
int v, e;
cin >> v >> e;
up(i, 0, e)
{
edge a;
int j,s, t;
cin >>j>> s >> t;
a.to = s;
a.cost = t;
g[j].push_back(a);//添加
}
return 0;
}
- 二分图判定
着色问题:把相邻顶点染成不同的颜色。
于是二分图的判定等价于颜色判定问题最小着色数是2的,便是二分图
typedef pair<int, int> pir;
vector<int >g[1000];//建立的无向无权图
int v;//顶点数目
int color[1000];//初始化为零,1,-1表示染色了或者没染色
bool dfs(int v, int c)
{
color[v] = c;//等于一个状态
for(auto k:g[v])//遍历v的节点
{
if (color[k] == c)return false;//有节点颜色和他一样的话
if (color[k] == 0 && !dfs(k, -c))return false;//下个节点可以达到但是染了不一样的颜色
}
return true;
}
void solve()
{
up(i, 0, v)
{
if (color[i] == 0)//防止他是森林有没有被遍历到的点
{
if (!dfs(i, 1))
{
cout << "no" << endl;
return;
}
}
}
cout << "yes" << endl;
}
- bell-man
直接上优化的代码
struct edge { int from, to, cost; };
edge es[1000];
int d[1000];//最短距离
int v, e;//顶点数和边数
bool find_loop(int s)
{
memset(d,maxn, sizeof(d));
d[s] = 0;//s为起点
bool b;//判断是不是已经做完了
bool c=false;//判断是不是有负圈
up(i, 0, v)
{
b = true;
up(j, 0, e)
{
edge e = es[j];
if (d[e.to] > d[e.from] + e.cost)
{
d[e.to] = d[e.from] + e.cost;//做松弛操作
b = false;
if (i == v - 1)//最多只会寻找v-1条边,从零开始遍历的话那么一共就只做v-2次
{
c = true;
break;
}
}
}
if (b) break;
if (c) break;
}
}
4.dijkstra
在没有负边的情况下,从顶点开始寻找到下一个权值最小的点,并保存。
这里写的是用堆优化后的代码。
因为每一次都只需要pop出来现在权值最小的点就好了。
struct edge { int to, cost; };//建立边集
typedef pair<int, int> p;
int v;//顶点
vector<edge> g[100];
int d[100];//费用
void dijkstra(int s)
{
priority_queue<p, vector< p >, greater< p > > que;//用小顶堆去维护
fill(d, d + v, maxn);//先填一个无穷大的数字
d[s] = 0;
que.push(p(0, s));//添加第一个顶点
while (!que.empty())
{
p p1 = que.top();//每一次取最小的那一个顶点出来
que.pop();
int v = p1.second;
if (d[v] < p1.first)continue;
for (auto k : g[v])//遍历该顶点所有的邻接点,有转移的入队。
{
if (d[k.to] > d[v] + k.cost)
{
d[k.to] = d[v] + k.cost;
que.push(p(d[k.to], k.to));
}
}
}
}
5.floyd-warshall
其实就是区间dp的思想,查找i-j之间任意点k是否存点i-k,k-j比之前的最优化方案还要优化的决策代码:
int d[1000][1000];//d[u][e]表示边集u,e的权值,不存在时设为负数,并且d[i][i]=0
int v;
void floyd()
{
up(k, 0, v)
{
up(i, 0, v)
{
up(j, 0, v)
{
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
}
6.最短路径打印
就是回溯的办法,在每一次转移的时候,保存一下当前节点是从哪个节点转移过来的,然后在逆推回去就行了。
7. prim
其实就是类似于贪心匹配,这里继续用堆来维护。
typedef pair<int, int > pir;
int in[100005];
int v, e;
vector<pir > g[10005];
int sum = 0;
int d[100];
bool use[100];
int prim()
{
fill(d, d + v, -100);
memset(use, false, sizeof(use));
priority_queue< pir, vector< pir >, greater< pir > > que;
pir p;
p.first = 0;
p.second = 1;
que.push(p);
while (!que.empty())
{
p = que.top();
que.pop();
if (use[p.second]) continue;
use[p.second] = true;
sum += p.first;
cout << "sum"<<sum<<endl;
for (auto k : g[p.second])
{
if (!use[k.second])
{
que.push(k);
}
}
}
return sum;
}
int main()
{
cin >> v >> e;
int x, y, z;
pir p;
up(i, 0, e)
{
cin >> x >> y >> z;
p.first = z;
p.second = y;
g[x].push_back(p);
p.second = x;
g[y].push_back(p);
}
int ans = prim();
cout << ans;
return 0;
}
- kruskal
相比较起来我还更喜欢kruskal emm…
struct edge{int u, v, cost;};
bool cmp(const edge& e1, const edge& e2)
{
return e1.cost < e2.cost;
}
edge es[100];
int v, e;
int kruskal()
{
sort(es, es + e, cmp);
init_union_find(v);//并查集,不让他成为圈
int res = 0;
for (int i = 0; i < e; i++)
{
edge e = es[i];
if (!same(e, u, e.v)) {
unite(e.u, e.v);
res += e.cost;//不是一个根才相加
}
}
return res;
}