题目描述
给出一个无向图,求出经过1的最小环
思路
这是某dalao的给的思路
这里做一下详细的补充
二进制优化:
因为每一条边都有唯一一个二进制
所有我们可以枚举二进制的每一位
若此位为0则给到1的出边,若为1则给到1的入边
然后将入1的边连向n+1(新),跑一边dij就行了
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define ll long long
using namespace std;
struct wh_
{
ll w, h, k, f;
}wh[10000250];
struct wh__
{
ll k, id;
bool operator < (const wh__ i)const
{
return (k != i.k) ? k < i.k : id < i.id;
}
};
priority_queue<wh__>hy;
ll Bol[500250], h[500250], Fla[10000250], B[500250];
ll dis[500250], log[10000250], Ru[500250];
ll n, m, tot, x, y, z1, z2, t, Ans;
inline ll read()
{
ll aba = 0, bab = 1; char c = getchar();
while(c < '0' || c > '9'){if(c == '-')bab = -1;c = getchar();}
while('0' <= c && c <= '9')aba = aba * 10 + c - 48, c = getchar();
return aba * bab;
}
void write(ll aba)
{if(aba > 9)write(aba / 10); putchar(aba % 10 + '0');}
ll Dij()
{
memset(dis, 0x7f, sizeof(dis));
memset(B, 0, sizeof(B));
dis[1] = 0;
hy.push((wh__){0, 1});
while(hy.size())
{
ll k = hy.top().id; hy.pop();
if(B[k])continue; B[k] = 1;
for(ll i = h[k]; i; i = wh[i].h)
{
if(wh[i].w == 1)continue;
if(wh[i].f == 1 && !Fla[i])continue;
if(dis[wh[i].w] > dis[k] + wh[i].k && !B[wh[i].w])
{
dis[wh[i].w] = dis[k] + wh[i].k;
hy.push((wh__){-dis[wh[i].w], wh[i].w});
}
}
}
return dis[n + 1];
}
void hw(ll x, ll y, ll z)
{wh[++t] = (wh_){y, h[x], z, x}; h[x] = t;}
int main()
{
n = read(), m = read();
log[1] = 0;
for(ll i = 2; i <= 2 * m; ++i)
log[i] = log[i >> 1] + 1;
for(ll i = 1; i <= m; ++i)
{
x = read(), y = read();
z1 = read(), z2 = read();
hw(x, y, z1), hw(y, x, z2);
}
Ans = 1e9;
for(ll i = 0; i <= log[t]; ++i)//枚举位数
{
memset(Bol, 0, sizeof(Bol));
memset(Fla, 0, sizeof(Fla));
memset(Ru, 0, sizeof(Ru));
tot = 0;
for(ll j = 1; j <= t; ++j)
{
if((j & (1 << i)) && wh[j].f == 1 && !Bol[wh[j].w])
Fla[j] = 1, Bol[wh[j].w] = 1;
else if(!(j & (1 << i)) && wh[j].w == 1 && !Bol[wh[j].f])
Ru[++tot] = j, wh[j].w = n + 1, Bol[wh[j].f] = 1;//连向n+1
}
Ans = min(Ans, Dij());
for(ll j = 1; j <= tot; ++j)wh[Ru[j]].w = 1;//连回1
memset(Bol, 0, sizeof(Bol));
memset(Fla, 0, sizeof(Fla));
memset(Ru, 0, sizeof(Ru));
tot = 0;
for(ll j = 1; j <= t; ++j)
{
if(!(j & (1 << i)) && wh[j].f == 1 && !Bol[wh[j].w])
Fla[j] = 1, Bol[wh[j].w] = 1;
else if((j & (1 << i)) && wh[j].w == 1 && !Bol[wh[j].f])
Ru[++tot] = j, wh[j].w = n + 1, Bol[wh[j].f] = 1;
}
Ans = min(Ans, Dij());
for(ll j = 1; j <= tot; ++j)wh[Ru[j]].w = 1;
}
write(Ans) ;
return 0;
}