关于生成图的总结

  1. 邻接表
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;
}
  1. 二分图判定
    着色问题:把相邻顶点染成不同的颜色。
    于是二分图的判定等价于颜色判定问题最小着色数是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;
}
  1. 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;
}
  1. 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值