初赛找环,复赛还是找环。初赛没有用到权重(金额),复赛对数据进行加强,同时对相邻两次转账的金额做了限制。
初赛用的单线程,最好成绩:0.2854, 进入了32强。复赛用了多线程,A榜最好成绩:6.1117。多线程负载均衡搞得很差,后面要多学习学习。
初赛最开始用的python,太耗时间了,根本没有办法比赛。这个比赛对于python 和 java选手是不太友好的。初赛后期就转为C++了,刚好可以学习一下C++。
第一次参加这种类型的比赛,总体的感受是收获很多,每天都能学到新的知识。之前没有学过数据结构,这次算是学到了点皮毛。之前写代码,耗时差不多就行,这次算是开了眼,前排大佬们各种骚操作。初赛最后,大佬们直接把线上数据集刺探透了,整个排行榜开始严重内卷。复赛初期,由于线上数据集太弱,又开始卷了。好在官方接受了选手们的意见,增强了数据集。
贴一下初赛的代码,复赛太长了就不贴了。
//
// Created by root on 4/10/20.
//
#include
#include
#include
#include
using namespace std;
//#define TEST
struct Edge
{
int ida;
int idb;
// int money;
};
struct Slice {
int* arr;
int n;
int* begin() { return arr; }
int* end() { return arr + n; }
};
#define edgesnum 280000
#define nodenum 280000
int feats[edgesnum][3]={0};//保存输入的边,起点id,终点id, 金额
int featscnt=0;
int nodeidmax = 0;
int graph[nodenum][50]={0}; //保存图,图的出度小于50
int graph_size[nodenum]={0};//保存每个点的出度数量
int graphR[nodenum][50]={0};//保存反向图,图的入度小于50
int graphR_size[nodenum]={0};//保存每个点的入度数量
char CID[nodenum][8]={"\0"};
char *(CIDpt[nodenum])={NULL};
int nodetoi[nodenum][50]={0}; // 保存以点j为起点,经过 k到达 i的路径。只用保存k就可以。
int nodetoi_size[nodenum]={0};
int res_cnt[8] = {0,0,0,0,0,0,0,0};
int res3[1000000][3]={0};//保存环3的结果
int res4[1000000][4]={0};
int res5[1000000][5]={0};
int res6[2000000][6]={0};
int res7[3000000][7]={0};//保存环7的结果
char buf[200000000];//保存最后要写入文件的内容
inline int fast_atoi( const char * str )
{
/*将字符串变成整型数*/
int val = 0;
while( *str!=',' ) {
val = val*10 + (*str++ - '0');
}
return val;
}
void load_testdata(string &test_dataf) {
char *buf;
int test_data_size = 0;
int fd = open(test_dataf.c_str(), O_RDONLY);
test_data_size = lseek(fd, 0, SEEK_END);
buf = (char*)mmap(NULL, test_data_size, PROT_READ, MAP_PRIVATE, fd, 0);
char *p = buf;
int temp1 = 0,temp2 = 0;
while((p-buf) < test_data_size) {
temp1 = fast_atoi(p);
while (*p != ',') // 其实这里可以fast_atoi放进来展开写,那样就舍去了下面的p++操作。但是改完发现变慢了一点,玄学了。
p++;
p++;
temp2 = fast_atoi(p);
while (*p != ',')
p++;
p++;
while (*p != '\n')// 由于不需要金额,就略过了。
p++;
p++;
feats[featscnt][0]=temp1;
feats[featscnt][1]=temp2;
featscnt+=1;
}
}
void build_graph()
{
/*建立正向图和反向图, 并对度数大于1的进行排序, 同时保存每个id的字符串*/
for(int i=0; i0 )
notemptycount1+=1;
}
#endif
for (int i=0; i< nodenum; ++i)
{
if (graph_size[i]>0) {
nodeidmax = i;
sprintf(CID[i], "%d", i);
CIDpt[i] = CID[i];
if (graph_size[i] > 1) {
sort(graph[i], graph[i] + graph_size[i]);
}
}
}
for (int i=0; i< nodenum; ++i) {
if (graphR_size[i] > 1) {
sort(graphR[i], graphR[i] + graphR_size[i]);
}
}
#ifdef TEST
//
int notemptycount2=0;
for (int i=0; i< nodenum; ++i)
{
if (graph_size[i]>0)
notemptycount2+=1;
}
cout<< "graph size(topobefore):" << notemptycount1 << " graph size(topoafter):" << notemptycount2 << endl;
#endif
}
void res_fromgraph()
{
/*开始找环, 对于每个起点i,先反向找2步,并且记录反向第3个点中能够到达i的点;再正向4步*/
/*每次对于小于i的直接剪掉,因为题目要求每个环的起点id要最小*/
// NodePath nodepath;
int pathtemp[7] = {0};
bool vist[nodenum]={false};
vector glrecord;
vector nodetoi_jumptwo_flag(nodenum, false);//jump two node
vector gjrecord;
vector nodetoi_flag(nodenum, false);//jump one node
int i = 0;
int loopnum = nodeidmax + 1;
for (; ii) {
nodetoi[gj][nodetoi_size[gj]] = gk;
++nodetoi_size[gj];
nodetoi_flag[gj] = true;
gjrecord.push_back(gj);
for(auto &gl:Slice{graphR[gj], graphR_size[gj]}){
if (gl>i and gl!=gk)
{ nodetoi_jumptwo_flag[gl] = true;
glrecord.push_back(gl);
}
}
}
}
}
vist[i] = true;
pathtemp[0] = i;
for(auto &node_j2: Slice{graph[i], graph_size[i]})
{
if (node_j2 < i)
continue;
vist[node_j2] = true;
pathtemp[1] = node_j2;
for (auto &node_j3:Slice{graph[node_j2], graph_size[node_j2]})
{
if (node_j3 <= i)
continue;
vist[node_j3] = true;
pathtemp[2] = node_j3;
for (auto &node_j4:Slice{graph[node_j3], graph_size[node_j3]})
{
if (node_j4 < i)
continue;
if (node_j4 == i)
{
memcpy(res3[res_cnt[3]], pathtemp, sizeof(int)*3);
++res_cnt[3];
continue;
}
if(vist[node_j4])
continue;
vist[node_j4] = true;
pathtemp[3] = node_j4;
if (nodetoi_flag[node_j4]) {
for (auto &node_j4toi:Slice{nodetoi[node_j4], nodetoi_size[node_j4]}) {
if (vist[node_j4toi]) {
continue;
}
pathtemp[4] = node_j4toi;
memcpy(res5[res_cnt[5]], pathtemp, sizeof(int)*5);
++res_cnt[5];
}
}
for (auto &node_j5:Slice{graph[node_j4], graph_size[node_j4]})
{
if (node_j5 < i)
continue;
if (node_j5 == i) {
memcpy(res4[res_cnt[4]], pathtemp, sizeof(int)*4);
++res_cnt[4];
continue;
}
if (vist[node_j5])
continue;
vist[node_j5] = true;
pathtemp[4] = node_j5;
if (nodetoi_flag[node_j5]){
for (auto &node_j5toi:Slice{nodetoi[node_j5], nodetoi_size[node_j5]}) {
if (vist[node_j5toi]) {
continue;
}
pathtemp[5] = node_j5toi;
memcpy(res6[res_cnt[6]], pathtemp, 24);
++res_cnt[6];
}
}
if (!nodetoi_jumptwo_flag[node_j5])
{
vist[node_j5] = false;
continue;
}
for (auto &node_j6:Slice{graph[node_j5], graph_size[node_j5]})
{
if (!vist[node_j6] and nodetoi_flag[node_j6])
{
pathtemp[5] = node_j6;
for (auto &node_j6toi:Slice{nodetoi[node_j6], nodetoi_size[node_j6]}) {
if (vist[node_j6toi])
continue;
else {
pathtemp[6] = node_j6toi;
memcpy(res7[res_cnt[7]], pathtemp, 28);
++res_cnt[7];
}
}
}
// vist[node_j6]=false;
}
vist[node_j5] = false;
}
vist[node_j4] = false;
}
vist[node_j3] = false;
}
vist[node_j2] = false;
}
vist[i] = false;
}
}
inline char* mystrcat( char* dest, char* src )
{
while (*dest) dest++;
while (*dest++ = *src++);
return --dest;
}
void save_fwrite(string &outfile){
/*保存输出*/
FILE *fp = fopen(outfile.c_str(), "wb");
char cntnum[50]={'\0'};
char *cntnumptr = cntnum;
char *bpt=buf;
int rescnt=0;
char idcomma = ',';
char idlf = '\n';
for (int i=3; i<8;++i)
{
rescnt += res_cnt[i];
}
sprintf(cntnum,"%d\n",rescnt);
bpt = mystrcat(bpt, cntnumptr);
int j = 0;
for (j=0; j