突然600多阅读我慌了。。感觉浪费大家赞了……
题目是http://codecraft.huawei.com/ 2016年初赛的题,类似TSP问题的那个……。
思路如下: 搜。
然后就傻乎乎搜炸了啊。。。
tarjan缩点后,DP剪枝去掉非法解(能去掉非常多的)。
结果依然是大数据出不了解。。。 所以我的方法非常烂啦
===================================
我们自以为很厉害的方法~实际上很垃圾,初赛20多分的样子,显然被刷啦~~~
但是毕竟做了。。代码保留一下就好了
往事不堪回首。。也不想读代码了。。直接看代码注释。。 这篇文章应该没人看吧…… 自己留纪念
#include "CheckMap.h"
#include
#include
using namespace std;
//已经开启了using namespace std了
unsigned long long start = clock();
CheckMap check(1, 1);
unsigned short final_ans = 1000; //默认初始最小答案
unsigned short edge_ans[max_vertex_num] = {0}, edge_ans_size = 0;
unsigned short tmp_edge[max_vertex_num];
ImportantMap init_next[max_vertex_num], final_status;
//6|28|34|8|21|15|25|10|13|14|31
void dfs(Vertex current_vertex, ImportantMap current_map, unsigned short current_ans, unsigned short deep)
{
if ( ((clock() - start) / (double)CLOCKS_PER_SEC) > 9.3) return;
if (current_ans >= final_status) return;
if (!check.check(current_vertex)) return; //查看这个节点是否能搜出来
//cout << current_vertex << " " << current_map <<" " << current_ans << " " << deep << endl;
if (current_vertex == check.end_vertex)//已经搜到终点啦
{
//因为有确保性原因,所以一定已经是解了?! 这个一会儿需要检测一下正确性
if (((current_map & final_status) == final_status) && current_ans < final_ans)
{
//cout << current_vertex << " " << current_map <<" " << current_ans << " " << deep << endl;
final_ans = current_ans;
edge_ans_size = deep;
memmove(edge_ans, tmp_edge, sizeof(short) * deep);
cout << final_ans << endl;
//for (int i = 0; i != edge_ans_size; ++ i)
// cout << edge_ans[i]<<" "; cout << endl;
}
return;
}
vis[current_vertex] = true; //访问标记
for (int i = 0; i != check.g[current_vertex].size(); ++ i)
{
Vertex will_vertex = check.g[current_vertex][i];
//cout << will_vertex << endl;
if (vis[will_vertex]) continue;//显然,已经访问过的,就不用访问
//cout << current_map <<" " << init_next[will_vertex]<<" " << final_status << endl;
if (((current_map | init_next[will_vertex]) & final_status) != final_status) continue;
tmp_edge[deep] = check.getEdgeNum(current_vertex , will_vertex);
if (will_vertex <= check.total_importan_vertex)
{
dfs( will_vertex,
current_map | (1<<(will_vertex - 1)),
current_ans + check.getDistance(current_vertex, will_vertex),
deep + 1);
}
else dfs( will_vertex,
current_map,//只保存访问过的重要点地图
current_ans + check.getDistance(current_vertex, will_vertex),
deep + 1);
}
vis[current_vertex] = false;
}
void init()
{
freopen("input.txt", "r", stdin);
int n, m;
cin >> n >> m;//点总数,边总数
for (int i = 0; i != m; ++ i)
{
unsigned short a, b, c, d;
cin >> a >> b >> c >> d;
check.insert(b, c, d, a); //b->c 距离是d,编号是a
}
unsigned short zhongyaodian;
cin >> zhongyaodian;
/*
* Init
* 把Map.h里的部分元素,进行清理。
* 修改起点, 终点,重要点的总量, 所有点的总量这4个参数
* */
check.setEndVertex(zhongyaodian); //设置重要的点的总量(终点)
check.setTotalVertex(n); //设置总的点的数量
check.setTotalImportanVertex(zhongyaodian); //设置重要点的总量
final_status = (1 << zhongyaodian) - 1;//全部访问完的状态
check.check(1);
for (int i = 1; i <= check.total_vertex; ++ i)
init_next[i] = check.f[check.belong[i]];
}
int main()
{
init();
//cout << final_status << endl;
dfs(1, 1, 0, 0);
for (int i = 0; i != edge_ans_size; ++ i)
cout << edge_ans[i]<<" "; cout << endl;
cout <<"this program runing-time is: "<< ((clock() - start) / (double)CLOCKS_PER_SEC) << " s, and the final distance is " <
#include "Map.h"
bool vis[max_vertex_num];
class CheckMap:public Map //生成一个Check变量,来完成所有的check操作
{
public:
unsigned short belong[max_vertex_num]; //原来每个点,所属的连通块
ImportantMap f[max_vertex_num];//f[i]表示i后继能到的点,包括自己
CheckMap(Vertex start, Vertex end):Map(start, end)
{
memset(vis, false, sizeof(vis));
clear();
}
void clear() //清理tarjan和BFS运算所需要的数组元素
{
memset(DFN, 0, sizeof(DFN));
memset(LOW, 0, sizeof(LOW));
memset(instack, 0, sizeof(instack));
memset(my_stack, 0, sizeof(my_stack));
memset(f, 0, sizeof(f));
memset(f_self, 0, sizeof(f_self));
memset(belong, 0, sizeof(belong));
memset(f_vis, false, sizeof(f_vis));//点是否被访问过,每个点只会被访问一次。(讲道理是这样)
Stop = din = count = 0;
}
void tarjan(Vertex current_vertex)
{
//cout << current_vertex << endl;
LOW[current_vertex] = DFN[current_vertex] = ++ din;
my_stack[++ Stop] = current_vertex;
instack[current_vertex] = true;
for (int i = 0; i != g[current_vertex].size(); ++ i)
{
Vertex will_vertex = g[current_vertex][i];
if (vis[will_vertex]) continue;//这个点已经在地图中被移除了
if (!DFN[will_vertex])
{
tarjan(will_vertex);
LOW[current_vertex] = min(LOW[current_vertex], LOW[will_vertex]);
}
else if (instack[will_vertex]) LOW[current_vertex] = min(LOW[current_vertex], DFN[will_vertex]);
}
if (LOW[current_vertex] == DFN[current_vertex])
{
Vertex tmp;
++count;
do
{
tmp = my_stack[Stop --];
instack[tmp] = false;
belong[tmp] = count;
if (tmp <= total_importan_vertex)//属于重要点的范畴
{
f[count] |= 1 << (tmp - 1); //f[count]这个连通块多了一些元素
}
}while (tmp != current_vertex);
}
}
//版本0.01的getF,看看能不能成功
ImportantMap getF(Vertex current_vertex)
{
if (f_vis[current_vertex] == true) return f[current_vertex];
f_vis[current_vertex] = true; //访问标记
if (current_vertex == belong[end_vertex])//如果已经到了end_vertex,那么显然不能走动了
{
return f[belong[end_vertex]];
}
for (int i = 0; i != new_g[current_vertex].size(); ++ i)
{
f[current_vertex] |= getF(new_g[current_vertex][i]);
}
return f[current_vertex];
}
bool findWay(Vertex current_vertex)//连通块,查看是否有解
{
if (DFN[current_vertex] != DFN[0]) return DFN[current_vertex];
if (current_vertex == belong[end_vertex])
{
if (f[current_vertex] == f[belong[end_vertex]])
{
return DFN[current_vertex] = true;
}
return false;
//如果到达最重点,并且最重点能遍历的情况,和当前情况相同则为true
}
for (int i = 0; i != new_g[current_vertex].size(); ++ i)
{
Vertex will_vertex = new_g[current_vertex][i];
if (current_vertex == will_vertex) continue;//自己到自己就有环了。。不能这样
// cout << current_vertex <<" " << will_vertex << endl;
if (f[will_vertex] == (f[current_vertex] ^ f_self[current_vertex]))
{
if (findWay(will_vertex))
{
return DFN[current_vertex] = true;
}
}
}
return DFN[current_vertex] = false;
}
bool check(Vertex current_vertex)//判断当前是否合法
{
//if (current_vertex == 4) cout<<"!!!!!"< new_g[max_vertex_num]; //缩点后的新图,路径不包含非法点
};//起点和终点都是1 需要后来修改
#include "preInclude.h"
class Map
{
public:
vector g[max_vertex_num]; //邻接表
unsigned short total_vertex; //最大的顶点标号,所有点的标号为1~total_vertex, 前面1~total_importan_vertex为重要点,其中1为起点,total_importan_vertex为终点
unsigned short total_importan_vertex; //全部重要点的数量
Vertex start_vertex; //起点标号。 一般为1
Vertex end_vertex; //终点标号, 一边为重要点的总数。
void setTotalVertex(short total_vertex) //修改最大顶点标号
{
this -> total_vertex = total_vertex;
}
inline void setTotalImportanVertex(unsigned short total_importan_vertex) //修改重要的点最大点标号
{
this -> total_importan_vertex = total_importan_vertex;
}
inline void insert(Vertex arg0, Vertex arg1, unsigned short distance, unsigned short edge_num)
//arg0 -> arg1 距离是distance ,边的标号是edge_num
{
if (this -> distance[arg0][arg1] > distance)
{
g[arg0].push_back(arg1);
this -> distance[arg0][arg1] = distance;
this -> edge_num[arg0][arg1] = edge_num;
}else
{
//do nothing
}
}
inline void setStartVertex(Vertex start_vertex)//修改起点标号
{
this -> start_vertex = start_vertex;
}
inline void setEndVertex(Vertex end_vertex)//修改终点标号
{
this -> end_vertex = end_vertex;
}
inline bool isConnected(Vertex arg0, Vertex arg1) //判断arg0和arg1是否连通
{
return edge_num[arg0][arg1] != null_distance;
}
inline unsigned short getDistance(Vertex arg0, Vertex arg1)// arg0->arg1的距离
{
return distance[arg0][arg1];
}
inline unsigned short getEdgeNum(Vertex arg0, Vertex arg1)//得到arg0->arg1的边
{
return edge_num[arg0][arg1];
}
Map(Vertex start, Vertex end):
start_vertex(start),end_vertex(end),
null_edge_num(56789),null_distance(56789) //构造函数,清空所有的变量
{
total_vertex = 0; //所有的顶点的数量为0,
for (int i = 0; i != max_vertex_num; i ++)
{
g[i].reserve(10);
for (int j = 0; j != max_vertex_num; j ++)
{
distance[i][j] = null_distance;
edge_num[i][j] = null_edge_num;
}
}
}
private:
unsigned short distance[max_vertex_num][max_vertex_num]; //距离矩阵
unsigned short edge_num[max_vertex_num][max_vertex_num]; //边标号矩阵,只记录最小的边标号
const unsigned short null_edge_num;
const unsigned short null_distance;
};
preinclude.h
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int max_vertex_num = 610;
typedef unsigned short StatusVertex;
typedef unsigned short Vertex;
typedef bitset BitSetMap;
typedef unsigned short Evaluation;
typedef unsigned long long ImportantMap;//二进制表示一个被遍历过的重要的点的信息,如果没遍历到就-1
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int max_vertex_num = 610;
const int null_num = 56789;
typedef unsigned short StatusVertex;
typedef unsigned short Vertex;
typedef bitset BitSetMap;
typedef unsigned short Evaluation;
typedef unsigned long long ImportantMap;//二进制表示一个被遍历过的重要的点的信息,如果没遍历到就-1
bool is_important_vertex[max_vertex_num]={0}; //is_important_vertex[i]==true表示i是否是重要点
class Status
{
public:
inline BitSetMap getBitSetMap() //返回当前地图
{
return traversed_map;
}
inline Vertex getCurrentVertex()//返回当前地图所停留的顶点
{
return current_vertex;
}
inline long getEvaluation() //返回估价值
{
return evaluation;
}
inline bool operator < (Status arg0) const
{
return evaluation < arg0.evaluation;
}
inline void setEvaluation(unsigned short evaluation)
{
this -> evaluation = evaluation;
}
inline bool isVisited(Vertex arg0)//arg0是否被访问过了
{
return traversed_map[arg0];
}
inline bool isAccessible(Vertex arg0)//arg0是否可以访问
{
return traversed_map[arg0] == 0;
}
Status()
{
current_ans = 0;
traversed_map =0;
evaluation =0;
current_vertex = 0;
traversed_important_vertexs = 0;
traversed_all_vertexs = 0;
}
private:
BitSetMap traversed_map; //保存整个地图的状态。 00001表示1号点被访问过了,00011 表示1,2都被访问过了。
Vertex current_vertex; //当前状态停留的顶点
unsigned short evaluation; //整个状态的估价值
unsigned short traversed_all_vertexs; //所有遍历过的点的数量
unsigned short traversed_important_vertexs; //所有被遍历过的重要点的数量
unsigned short current_ans; //当前状态距离起点的距离
};
class RoadStatus
{
public:
bool isLegalSolution() //这个状态是否合法,是否存在路径到终点
{
return is_legal_solution;
}
bool setLegalSolution(bool flag)
{
is_legal_solution = flag;
}
private:
bool is_legal_solution;
};
class Map
{
public:
vector g[max_vertex_num]; //邻接表
unsigned short total_vertex; //最大的顶点标号,所有点的标号为1~total_vertex, 前面1~total_importan_vertex为重要点,其中1为起点,total_importan_vertex为终点
unsigned short total_importan_vertex;
Vertex start_vertex;
Vertex end_vertex;
void setTotalVertex(short total_vertex) //修改最大顶点标号
{
this -> total_vertex = total_vertex;
}
inline void setTotalImportanVertex(unsigned short total_importan_vertex) //修改重要的点最大点标号
{
this -> total_importan_vertex = total_importan_vertex;
}
inline void insert(Vertex arg0, Vertex arg1, unsigned short distance, unsigned short edge_num)
//arg0 -> arg1 距离是distance ,边的标号是edge_num
{
if (this -> distance[arg0][arg1] > distance)
{
g[arg0].push_back(arg1);
this -> distance[arg0][arg1] = distance;
this -> edge_num[arg0][arg1] = edge_num;
}else
{
//do nothing
}
}
inline void setStartVertex(Vertex start_vertex)
{
this -> start_vertex = start_vertex;
}
inline void setEndVertex(Vertex end_vertex)
{
this -> end_vertex = end_vertex;
}
inline bool isConnected(Vertex arg0, Vertex arg1) //判断arg0和arg1是否连通
{
// return edge_num[arg0][arg1] != null_distance;
}
inline unsigned short getDistance(Vertex arg0, Vertex arg1)
{
return distance[arg0][arg1];
}
Map(Vertex start, Vertex end):
start_vertex(start),end_vertex(end),
null_edge_num(56789),null_distance(56789) //构造函数,清空所有的变量
{
total_vertex = 0; //所有的顶点的数量为0,
for (int i = 0; i != max_vertex_num; i ++)
{
g[i].reserve(10);
for (int j = 0; j != max_vertex_num; j ++)
{
distance[i][j] = null_distance;
edge_num[i][j] = null_edge_num;
}
}
}
private:
unsigned short distance[max_vertex_num][max_vertex_num]; //距离矩阵
unsigned short edge_num[max_vertex_num][max_vertex_num]; //边标号矩阵,只记录最小的边标号
const unsigned short null_edge_num;
const unsigned short null_distance;
};
class CheckMap:public Map //生成一个Check变量,来完成所有的check操作
{
public:
/*
CheckMap():Map()//初始化的时候,先调用Map初始化一下
{
clear();
}*/
//CheckMap(){}
CheckMap(Vertex start, Vertex end):Map(start, end)
{
clear();
}
void clear() //清理tarjan和BFS运算所需要的数组元素
{
memset(DFN, 0, sizeof(DFN));
memset(LOW, 0, sizeof(LOW));
memset(instack, 0, sizeof(instack));
memset(my_stack, 0, sizeof(my_stack));
memset(f, 0, sizeof(f));
memset(belong, 0, sizeof(belong));
memset(belong_vertex_evaluation, 2, sizeof(belong_vertex_evaluation)); //数组清最大值
memset(f_vis, false, sizeof(f_vis));//点是否被访问过,每个点只会被访问一次。(讲道理是这样)
Stop = din = count = 0;
total_evaluation_valve = 0; //估价清0
}
void tarjan(Vertex current_vertex)
{
LOW[current_vertex] = DFN[current_vertex] = ++ din;
my_stack[++ Stop] = current_vertex;
instack[current_vertex] = true;
for (int i = 0; i != g[current_vertex].size(); ++ i)
{
int will_vertex = g[current_vertex][i];
if (map_status.isVisited(will_vertex)) continue;//这个点已经在地图中被移除了
if (!DFN[will_vertex])
{
tarjan(will_vertex);
LOW[current_vertex] = min(LOW[current_vertex], LOW[will_vertex]);
}
else if (instack[will_vertex]) LOW[current_vertex] = min(LOW[current_vertex], DFN[will_vertex]);
}
if (LOW[current_vertex] == DFN[current_vertex])
{
int tmp;
++count;
do
{
tmp = my_stack[Stop --];
instack[tmp] = false;
belong[tmp] = count;
if (tmp <= total_importan_vertex)//属于重要点的范畴
{
f[count] |= 1 << (tmp - 1); //f[count]这个连通块多了一些元素
}
}while (tmp != current_vertex);
}
}
StatusVertex evaluationVertexLiantong(Vertex current_vertex)
{
unsigned short lei = belong[current_vertex]; //只能走这个种类的点
DFN[current_vertex] = true; //访问标记
//DFN[i]
for (int i = 0; i != g[current_vertex].size(); i ++ )
{
Vertex will_vertex = g[current_vertex][i];
if (belong[will_vertex] != lei || current_status.isVisited(will_vertex)) continue;
total_evaluation_valve += getDistance(current_vertex, will_vertex);
evaluationVertexLiantong(will_vertex);
}
}
//版本0.01的getF,看看能不能成功
ImportantMap getF(Vertex current_vertex)
{
if (f_vis[current_vertex] == true) return f[current_vertex];
f_vis[current_vertex] = true; //访问标记
if (current_vertex == end_vertex)//如果已经到了end_vertex,那么显然不能走动了
{
return f[belong[end_vertex]];
}
for (int i = 0; i != g[current_vertex].size(); ++ i)
{
f[current_vertex] |= getF(g[current_vertex][i]);
}
return f[current_vertex];
}
bool findWay(Vertex current_vertex)//连通块,查看是否有解
{
if (current_vertex == end_vertex)
{
if (f[current_vertex] == f[belong[end_vertex]]) return true;
//如果到达最重点,并且最重点能遍历的情况,和当前情况相同则为true
}
for (int i = 0; i != new_g[current_vertex].size(); ++ i)
{
Vertex will_vertex = new_g[current_vertex][i];
if (f[will_vertex] == (f[current_vertex] ^ f_self[current_vertex]))
{
if (findWay(will_vertex)) return true;
}
}
return false;
}
RoadStatus check(Status current_status)//当前路径状态
{
this -> current_status = current_status;
RoadStatus check_ret;
clear(); //先清空所有数组元素
Vertex current_vertex = current_status.getCurrentVertex();//得到当前顶点
for (int i = 0; i <= total_vertex; i ++)
if (current_status.isVisited(i) && !DFN[i]) tarjan(i);//缩点
memmove(f_self, f, sizeof(f_self)); //f_self全部是都是每个点自己的状态
for (int i = 0; i <= total_vertex; i ++)//重新构图
{
g[i].clear();
for (int j = 0; j != g[i].size(); ++ j)
{
if (map_status.isVisited(g[i][j])) continue;
//新构的图,不包含非法路径,因为垃圾点直接就不在图里
new_g[belong[i]].push_back(belong[g[i][j]]);
belong_vertex_evaluation[belong[g[i][j]]] = //更新每个连通块入度最小值
min(belong_vertex_evaluation[belong[g[i][j]]], getDistance(belong[i], belong[g[i][j]]));
//belong[i] - > belong[g[i][j]]
}
}
getF(belong[current_vertex]);//做一个DP,得到f数组
check_ret.setLegalSolution(findWay(belong[current_vertex]));
if (!check_ret.isLegalSolution()) return check_ret; //非法解,退出
/*开始估价每个连通块入度的总权重*/
for (int i = 1; i <= count; ++ i)
{
if (belong_vertex_evaluation[i] == belong_vertex_evaluation[0]) continue; //连通块入度为0,就直接continue
total_evaluation_valve += belong_vertex_evaluation[i];//每个状态的入度增加
}
/*开始对每个连通块的权重进行估价*/
memset(f_vis, false, sizeof(f_vis));//这个访问标记数组又要用了,是否访问表示连通块是否访问过
memset(DFN, false, sizeof(DFN)); // dfn[i]现在为某个点是否访问过了
for (int i = 1; i <= total_vertex; ++ i)
{
if (current_status.isAccessible(i) || f_vis[belong[i]]) continue;
f_vis[belong[i]] = true;
evaluationVertexLiantong(i);
// belong[i] i所属连通块
}
}
private:
Status current_status; //当前路径状态
unsigned short DFN[max_vertex_num]; //时间戳
unsigned short LOW[max_vertex_num]; //最早追溯到的时间戳
bool instack[max_vertex_num]; // 顶点是否属于栈
unsigned short my_stack[max_vertex_num]; //手写的一个简单的栈
unsigned short belong[max_vertex_num]; //原来每个点,所属的连通块
unsigned short Stop, din, count;//栈顶编号0~?, 时间戳编号1~?, 缩点后,每个连通块的编号1~?
bool f_vis[max_vertex_num];
unsigned short belong_vertex_evaluation[max_vertex_num]; //每个连通块入度最小的值
ImportantMap f_self[max_vertex_num]; //f_self[i]表示i这个连通块里自己所拥有的重要的点
ImportantMap f[max_vertex_num];//f[i]表示i后继能到的点
vector new_g[max_vertex_num]; //缩点后的新图,路径不包含非法点
unsigned short total_evaluation_valve; // 计算状态的估价
Status map_status; //传递过来处理的map状态
}check(1, 1);//起点和终点都是1,需要后来修改
int getnum()
{
return (rand() % 10) + 1;
}
int main()
{
freopen("input.txt", "r", stdin);
int n, m;
cin >> n >> m;
//srand(100);
for (int i = 0; i != m; ++ i)
{
int a, b;
cin >> a >> b;
check.insert(i, a, b, 1); //随机给定一个权重
}
int zhongyaodian;
cin >> zhongyaodian;
check.setEndVertex(zhongyaodian);
return 0;
}
check_dag.cpp
#include
#include
#include
#include
#include
#include